mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-15 20:45:45 +03:00
Merge pull request #21200 from ChayimFriedman2/fake-impls
perf: Do not really expand builtin derives, instead treat them specifically
This commit is contained in:
@@ -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 @@ pub struct AttrFlags: u64 {
|
||||
const RUSTC_PAREN_SUGAR = 1 << 42;
|
||||
const RUSTC_COINDUCTIVE = 1 << 43;
|
||||
const RUSTC_FORCE_INLINE = 1 << 44;
|
||||
const IS_POINTEE = 1 << 45;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 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 @@ pub fn impls(&self) -> impl ExactSizeIterator<Item = ImplId> + '_ {
|
||||
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 @@ pub(crate) fn define_impl(&mut self, imp: ImplId) {
|
||||
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 @@ pub(crate) fn init_derive_attribute(
|
||||
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 @@ pub(crate) fn shrink_to_fit(&mut self) {
|
||||
unresolved,
|
||||
declarations,
|
||||
impls,
|
||||
builtin_derive_impls,
|
||||
unnamed_consts,
|
||||
unnamed_trait_imports,
|
||||
legacy_macros,
|
||||
@@ -834,6 +845,7 @@ pub(crate) fn shrink_to_fit(&mut self) {
|
||||
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 @@
|
||||
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 @@ fn collect_lang_item<T>(&mut self, db: &dyn DefDatabase, item: T)
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ pub struct $LangItems {
|
||||
$(#[$attr])*
|
||||
pub $lang_item: Option<$target>,
|
||||
)*
|
||||
$(
|
||||
pub $non_lang_trait: Option<TraitId>,
|
||||
)*
|
||||
}
|
||||
|
||||
impl LangItems {
|
||||
@@ -176,6 +213,7 @@ fn is_empty(&self) -> bool {
|
||||
/// 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 @@ fn assign_lang_item(&mut self, name: Symbol, target: LangItemTarget) {
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ pub fn from_symbol(symbol: &Symbol) -> Option<Self> {
|
||||
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 item_tree;
|
||||
|
||||
pub mod builtin_derive;
|
||||
pub mod lang_item;
|
||||
|
||||
pub mod hir;
|
||||
@@ -63,6 +64,7 @@
|
||||
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 @@
|
||||
|
||||
use crate::{
|
||||
attrs::AttrFlags,
|
||||
builtin_derive::BuiltinDeriveImplTrait,
|
||||
builtin_type::BuiltinType,
|
||||
db::DefDatabase,
|
||||
expr_store::ExpressionStoreSourceMap,
|
||||
@@ -331,6 +334,21 @@ pub fn impl_items_with_diagnostics(self, db: &dyn DefDatabase) -> &(ImplItems, D
|
||||
}
|
||||
}
|
||||
|
||||
#[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 @@ pub enum ModuleDefId {
|
||||
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 @@
|
||||
|
||||
#[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 @@
|
||||
|
||||
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 @@
|
||||
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 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 @@ fn push_res_and_update_glob_vis(
|
||||
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 @@ enum Resolved {
|
||||
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 @@ enum Resolved {
|
||||
);
|
||||
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 @@ enum Resolved {
|
||||
.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 @@ enum Resolved {
|
||||
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 @@ enum Resolved {
|
||||
*derive_pos as u32,
|
||||
*call_site,
|
||||
self.def_map.krate,
|
||||
resolver,
|
||||
|path| resolver(&self.def_map, path),
|
||||
*derive_macro_id,
|
||||
);
|
||||
|
||||
@@ -1354,7 +1374,8 @@ enum Resolved {
|
||||
}
|
||||
}
|
||||
|
||||
push_resolved(directive, call_id);
|
||||
push_resolved(&mut resolved, directive, call_id);
|
||||
|
||||
res = ReachedFixedPoint::No;
|
||||
return Resolved::Yes;
|
||||
}
|
||||
@@ -1460,29 +1481,85 @@ enum Resolved {
|
||||
|
||||
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 @@ enum Resolved {
|
||||
// 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 @@ enum Resolved {
|
||||
}
|
||||
}
|
||||
|
||||
// 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 @@ fn finish(mut self) -> (DefMap, LocalDefMap) {
|
||||
));
|
||||
}
|
||||
|
||||
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 @@ fn collect(&mut self, items: &[ModItemId], container: ItemContainerId) {
|
||||
}
|
||||
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 @@ fn collect(&mut self, items: &[ModItemId], container: ItemContainerId) {
|
||||
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 @@ fn collect(&mut self, items: &[ModItemId], container: ItemContainerId) {
|
||||
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 @@ fn collect(&mut self, items: &[ModItemId], container: ItemContainerId) {
|
||||
}
|
||||
.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 @@ fn expand_derive() {
|
||||
#[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 @@ fn builtin_derive_with_unresolved_attributes_fall_back() {
|
||||
#[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 @@
|
||||
};
|
||||
|
||||
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 @@ fn find_by_name(name: &name::Name) -> Option<Self> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -75,7 +74,7 @@ pub fn expand(
|
||||
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> {
|
||||
|
||||
@@ -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 @@ fn clone(&self) -> S {
|
||||
}
|
||||
|
||||
#[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 @@ fn lookup_impl_method<'db>(
|
||||
env: ParamEnvAndCrate<'db>,
|
||||
func: FunctionId,
|
||||
fn_subst: GenericArgs<'db>,
|
||||
) -> (FunctionId, GenericArgs<'db>);
|
||||
) -> (Either<FunctionId, (BuiltinDeriveImplId, BuiltinDeriveImplMethod)>, GenericArgs<'db>);
|
||||
|
||||
// endregion:mir
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
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 @@ fn contains(&self, proj: &AliasTy<'db>) -> bool {
|
||||
}
|
||||
|
||||
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 self as hir_ty;
|
||||
|
||||
pub mod builtin_derive;
|
||||
mod infer;
|
||||
mod inhabitedness;
|
||||
mod lower;
|
||||
|
||||
@@ -1790,6 +1790,13 @@ pub fn query_with_diagnostics(
|
||||
}
|
||||
|
||||
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_query<'db>(
|
||||
) -> 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 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 @@
|
||||
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 @@ pub fn for_each_crate_and_block(
|
||||
|
||||
#[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 @@ fn finish(self) -> OneTraitImpls {
|
||||
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 @@ pub fn for_crate_and_deps(db: &dyn HirDatabase, krate: Crate) -> Box<[Arc<Self>]
|
||||
|
||||
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 @@ fn collect_def_map(db: &dyn HirDatabase, def_map: &DefMap) -> Self {
|
||||
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 @@ fn collect(
|
||||
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 @@ pub fn has_impls_for_trait_and_self_ty(
|
||||
})
|
||||
}
|
||||
|
||||
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 @@ fn assemble_inherent_impl_probe(&mut self, impl_def_id: ImplId, receiver_steps:
|
||||
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 @@ fn select_trait_candidate(
|
||||
/// 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 @@ fn candidate_source(&self, candidate: &Candidate<'db>, self_ty: Ty<'db>) -> Cand
|
||||
|
||||
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 @@ fn get_mir_or_dyn_index(
|
||||
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 @@
|
||||
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 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 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
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 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
ConstId,
|
||||
FunctionId,
|
||||
ImplId,
|
||||
BuiltinDeriveImplId,
|
||||
StaticId,
|
||||
TraitId,
|
||||
TypeAliasId,
|
||||
@@ -170,7 +173,8 @@ fn try_from(value: SolverDefId) -> Result<Self, Self::Error> {
|
||||
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 @@ fn try_from(value: SolverDefId) -> Result<Self, Self::Error> {
|
||||
| SolverDefId::TraitId(_)
|
||||
| SolverDefId::TypeAliasId(_)
|
||||
| SolverDefId::ImplId(_)
|
||||
| SolverDefId::BuiltinDeriveImplId(_)
|
||||
| SolverDefId::InternedClosureId(_)
|
||||
| SolverDefId::InternedCoroutineId(_)
|
||||
| SolverDefId::Ctor(Ctor::Struct(_))
|
||||
@@ -216,6 +221,7 @@ fn try_from(value: SolverDefId) -> Result<Self, Self::Error> {
|
||||
| SolverDefId::InternedCoroutineId(_)
|
||||
| SolverDefId::InternedOpaqueTyId(_)
|
||||
| SolverDefId::EnumVariantId(_)
|
||||
| SolverDefId::BuiltinDeriveImplId(_)
|
||||
| SolverDefId::Ctor(_) => return Err(()),
|
||||
})
|
||||
}
|
||||
@@ -241,28 +247,6 @@ pub fn expect_type_alias(self) -> TypeAliasId {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ fn is_local(self) -> bool {
|
||||
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 @@ fn is_local(self) -> bool {
|
||||
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 @@ fn get_impl_header(&self, candidate: &InspectCandidate<'_, 'db>) -> Option<Strin
|
||||
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 @@
|
||||
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 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 @@ pub(crate) fn map<M, F>(self, f: F) -> ImplSource<'db, M>
|
||||
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 @@
|
||||
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 @@ fn expand_abstract_consts<T: rustc_type_ir::TypeFoldable<Self>>(self, _: T) -> T
|
||||
}
|
||||
|
||||
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 @@ fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf {
|
||||
| SolverDefId::TraitId(_)
|
||||
| SolverDefId::TypeAliasId(_)
|
||||
| SolverDefId::ImplId(_)
|
||||
| SolverDefId::BuiltinDeriveImplId(_)
|
||||
| SolverDefId::InternedClosureId(_)
|
||||
| SolverDefId::InternedCoroutineId(_) => {
|
||||
return VariancesOf::empty(self);
|
||||
@@ -1327,6 +1328,7 @@ fn parent(self, def_id: Self::DefId) -> Self::DefId {
|
||||
| SolverDefId::AdtId(_)
|
||||
| SolverDefId::TraitId(_)
|
||||
| SolverDefId::ImplId(_)
|
||||
| SolverDefId::BuiltinDeriveImplId(_)
|
||||
| SolverDefId::EnumVariantId(..)
|
||||
| SolverDefId::Ctor(..)
|
||||
| SolverDefId::InternedOpaqueTyId(..) => panic!(),
|
||||
@@ -1445,8 +1447,7 @@ fn predicates_of(
|
||||
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 @@ fn own_predicates_of(
|
||||
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 @@ fn is_self_or_assoc(ty: Ty<'_>) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ fn for_each_relevant_impl(
|
||||
SolverDefId::ConstId(_)
|
||||
| SolverDefId::FunctionId(_)
|
||||
| SolverDefId::ImplId(_)
|
||||
| SolverDefId::BuiltinDeriveImplId(_)
|
||||
| SolverDefId::StaticId(_)
|
||||
| SolverDefId::InternedClosureId(_)
|
||||
| SolverDefId::InternedCoroutineId(_)
|
||||
@@ -1805,7 +1804,12 @@ fn for_each_relevant_impl(
|
||||
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 @@ fn has_item_definition(self, _def_id: Self::DefId) -> bool {
|
||||
}
|
||||
|
||||
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 @@ fn impl_trait_ref(
|
||||
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 @@ fn impl_specializes(
|
||||
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 @@ pub fn mk_fn_sig<I>(
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ fn generic_visit_with(&self, _visitor: &mut V) {}
|
||||
ClosureIdWrapper,
|
||||
CoroutineIdWrapper,
|
||||
AdtIdWrapper,
|
||||
ImplIdWrapper,
|
||||
AnyImplId,
|
||||
GeneralConstIdWrapper,
|
||||
Safety,
|
||||
FnAbi,
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
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 @@ fn fetch_eligible_assoc_item(
|
||||
&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 @@ fn bar() -> f32 {
|
||||
"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 @@ fn bar() -> f32 {
|
||||
"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 @@ fn bar() -> f32 {
|
||||
"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 @@ pub struct SomeStruct {
|
||||
"parse_shim",
|
||||
"real_span_map_shim",
|
||||
"TraitImpls::for_crate_",
|
||||
"lang_items",
|
||||
"crate_lang_items",
|
||||
"AttrFlags::query_",
|
||||
"AttrFlags::query_",
|
||||
"AttrFlags::query_",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
@@ -501,17 +532,16 @@ pub fn new(value: i32) -> Self {
|
||||
"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 @@ pub fn doc_aliases<'db>(&self, db: &'db dyn HirDatabase) -> &'db [Symbol] {
|
||||
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 @@ pub fn cfgs<'db>(&self, db: &'db dyn HirDatabase) -> Option<&'db CfgExpr> {
|
||||
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 @@ pub fn hir_docs<'db>(&self, db: &'db dyn HirDatabase) -> Option<&'db Docs> {
|
||||
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 @@ fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner {
|
||||
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 @@ fn hir_docs(self, db: &dyn HirDatabase) -> Option<&Docs> {
|
||||
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 @@ fn attr_id(self, _db: &dyn HirDatabase) -> AttrsOwner {
|
||||
(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 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 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
|
||||
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 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
|
||||
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 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
|
||||
}
|
||||
|
||||
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 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
|
||||
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 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ fn from(ty: $ty) -> $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 @@ fn from(id: ModuleDefId) -> Self {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ fn from(id: ModuleDef) -> Self {
|
||||
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 @@ fn from(def: AssocItemId) -> Self {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ fn from(def: FieldId) -> Self {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ fn from(it: hir_def::item_scope::ItemInNs) -> Self {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ fn from(it: BuiltinType) -> Self {
|
||||
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 @@
|
||||
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 @@ fn source(self, db: &dyn HirDatabase) -> Option<InFile<ast::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 @@ fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
|
||||
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())
|
||||
|
||||
@@ -48,12 +48,13 @@
|
||||
use base_db::{CrateDisplayName, CrateOrigin, LangCrateOrigin};
|
||||
use either::Either;
|
||||
use hir_def::{
|
||||
AdtId, AssocItemId, AssocItemLoc, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId,
|
||||
EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, GenericDefId, GenericParamId,
|
||||
HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, MacroExpander,
|
||||
MacroId, StaticId, StructId, SyntheticSyntax, TupleId, TypeAliasId, TypeOrConstParamId,
|
||||
TypeParamId, UnionId,
|
||||
AdtId, AssocItemId, AssocItemLoc, BuiltinDeriveImplId, CallableDefId, ConstId, ConstParamId,
|
||||
DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, GenericDefId,
|
||||
GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup,
|
||||
MacroExpander, MacroId, StaticId, StructId, SyntheticSyntax, TupleId, TypeAliasId,
|
||||
TypeOrConstParamId, TypeParamId, UnionId,
|
||||
attrs::AttrFlags,
|
||||
builtin_derive::BuiltinDeriveImplMethod,
|
||||
expr_store::{ExpressionStoreDiagnostics, ExpressionStoreSourceMap},
|
||||
hir::{
|
||||
BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, LabelId, Pat,
|
||||
@@ -73,7 +74,8 @@
|
||||
visibility::visibility_from_ast,
|
||||
};
|
||||
use hir_expand::{
|
||||
AstId, MacroCallKind, RenderedExpandError, ValueResult, proc_macro::ProcMacroKind,
|
||||
AstId, MacroCallKind, RenderedExpandError, ValueResult, builtin::BuiltinDeriveExpander,
|
||||
proc_macro::ProcMacroKind,
|
||||
};
|
||||
use hir_ty::{
|
||||
GenericPredicates, InferenceResult, ParamEnvAndCrate, TyDefId, TyLoweringDiagnostic,
|
||||
@@ -88,8 +90,9 @@
|
||||
},
|
||||
mir::{MutBorrowKind, interpret_mir},
|
||||
next_solver::{
|
||||
AliasTy, ClauseKind, ConstKind, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs,
|
||||
ParamEnv, PolyFnSig, Region, SolverDefId, Ty, TyKind, TypingMode,
|
||||
AliasTy, AnyImplId, ClauseKind, ConstKind, DbInterner, EarlyBinder, EarlyParamRegion,
|
||||
ErrorGuaranteed, GenericArg, GenericArgs, ParamConst, ParamEnv, PolyFnSig, Region,
|
||||
RegionKind, SolverDefId, Ty, TyKind, TypingMode,
|
||||
infer::{DbInternerInferExt, InferCtxt},
|
||||
},
|
||||
traits::{self, is_inherent_impl_coherent, structurally_normalize_ty},
|
||||
@@ -97,7 +100,8 @@
|
||||
use itertools::Itertools;
|
||||
use rustc_hash::FxHashSet;
|
||||
use rustc_type_ir::{
|
||||
AliasTyKind, TypeSuperVisitable, TypeVisitable, TypeVisitor, fast_reject,
|
||||
AliasTyKind, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable,
|
||||
TypeVisitor, fast_reject,
|
||||
inherent::{AdtDef, GenericArgs as _, IntoKind, SliceLike, Term as _, Ty as _},
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
@@ -105,7 +109,7 @@
|
||||
use stdx::{format_to, impl_from, never, variance::PhantomCovariantLifetime};
|
||||
use syntax::{
|
||||
AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, TextRange, ToSmolStr,
|
||||
ast::{self, HasName, HasVisibility as _},
|
||||
ast::{self, HasName as _, HasVisibility as _},
|
||||
format_smolstr,
|
||||
};
|
||||
use triomphe::{Arc, ThinArc};
|
||||
@@ -440,7 +444,10 @@ pub fn diagnostics<'db>(
|
||||
Adt::Union(it) => it.id.into(),
|
||||
},
|
||||
ModuleDef::Trait(it) => it.id.into(),
|
||||
ModuleDef::Function(it) => it.id.into(),
|
||||
ModuleDef::Function(it) => match it.id {
|
||||
AnyFunctionId::FunctionId(it) => it.into(),
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { .. } => return Vec::new(),
|
||||
},
|
||||
ModuleDef::TypeAlias(it) => it.id.into(),
|
||||
ModuleDef::Module(it) => it.id.into(),
|
||||
ModuleDef::Const(it) => it.id.into(),
|
||||
@@ -504,7 +511,7 @@ pub fn as_self_generic_def(self) -> Option<GenericDef> {
|
||||
pub fn attrs(&self, db: &dyn HirDatabase) -> Option<AttrsWithOwner> {
|
||||
Some(match self {
|
||||
ModuleDef::Module(it) => it.attrs(db),
|
||||
ModuleDef::Function(it) => it.attrs(db),
|
||||
ModuleDef::Function(it) => HasAttrs::attrs(*it, db),
|
||||
ModuleDef::Adt(it) => it.attrs(db),
|
||||
ModuleDef::Variant(it) => it.attrs(db),
|
||||
ModuleDef::Const(it) => it.attrs(db),
|
||||
@@ -772,8 +779,11 @@ pub fn diagnostics<'db>(
|
||||
for impl_def in self.impl_defs(db) {
|
||||
GenericDef::Impl(impl_def).diagnostics(db, acc);
|
||||
|
||||
let loc = impl_def.id.lookup(db);
|
||||
let (impl_signature, source_map) = db.impl_signature_with_source_map(impl_def.id);
|
||||
let AnyImplId::ImplId(impl_id) = impl_def.id else {
|
||||
continue;
|
||||
};
|
||||
let loc = impl_id.lookup(db);
|
||||
let (impl_signature, source_map) = db.impl_signature_with_source_map(impl_id);
|
||||
expr_store_diagnostics(db, acc, &source_map);
|
||||
|
||||
let file_id = loc.id.file_id;
|
||||
@@ -789,12 +799,12 @@ pub fn diagnostics<'db>(
|
||||
|
||||
let ast_id_map = db.ast_id_map(file_id);
|
||||
|
||||
for diag in impl_def.id.impl_items_with_diagnostics(db).1.iter() {
|
||||
for diag in impl_id.impl_items_with_diagnostics(db).1.iter() {
|
||||
emit_def_diagnostic(db, acc, diag, edition, loc.container.krate(db));
|
||||
}
|
||||
|
||||
if impl_signature.target_trait.is_none()
|
||||
&& !is_inherent_impl_coherent(db, def_map, impl_def.id)
|
||||
&& !is_inherent_impl_coherent(db, def_map, impl_id)
|
||||
{
|
||||
acc.push(IncoherentImpl { impl_: ast_id_map.get(loc.id.value), file_id }.into())
|
||||
}
|
||||
@@ -822,7 +832,7 @@ pub fn diagnostics<'db>(
|
||||
if drop_trait != trait_.into() {
|
||||
return None;
|
||||
}
|
||||
let parent = impl_def.id.into();
|
||||
let parent = impl_id.into();
|
||||
let (lifetimes_attrs, type_and_consts_attrs) =
|
||||
AttrFlags::query_generic_params(db, parent);
|
||||
let res = lifetimes_attrs.values().any(|it| it.contains(AttrFlags::MAY_DANGLE))
|
||||
@@ -851,7 +861,7 @@ pub fn diagnostics<'db>(
|
||||
AssocItemId::ConstId(id) => !db.const_signature(id).has_body(),
|
||||
AssocItemId::TypeAliasId(it) => db.type_alias_signature(it).ty.is_none(),
|
||||
});
|
||||
impl_assoc_items_scratch.extend(impl_def.id.impl_items(db).items.iter().cloned());
|
||||
impl_assoc_items_scratch.extend(impl_id.impl_items(db).items.iter().cloned());
|
||||
|
||||
let redundant = impl_assoc_items_scratch
|
||||
.iter()
|
||||
@@ -883,11 +893,11 @@ pub fn diagnostics<'db>(
|
||||
.collect();
|
||||
|
||||
if !missing.is_empty() {
|
||||
let self_ty = db.impl_self_ty(impl_def.id).instantiate_identity();
|
||||
let self_ty = db.impl_self_ty(impl_id).instantiate_identity();
|
||||
let self_ty = structurally_normalize_ty(
|
||||
&infcx,
|
||||
self_ty,
|
||||
db.trait_environment(impl_def.id.into()),
|
||||
db.trait_environment(impl_id.into()),
|
||||
);
|
||||
let self_ty_is_guaranteed_unsized = matches!(
|
||||
self_ty.kind(),
|
||||
@@ -896,7 +906,13 @@ pub fn diagnostics<'db>(
|
||||
if self_ty_is_guaranteed_unsized {
|
||||
missing.retain(|(_, assoc_item)| {
|
||||
let assoc_item = match *assoc_item {
|
||||
AssocItem::Function(it) => it.id.into(),
|
||||
AssocItem::Function(it) => match it.id {
|
||||
AnyFunctionId::FunctionId(id) => id.into(),
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { .. } => {
|
||||
never!("should not have an `AnyFunctionId::BuiltinDeriveImplMethod` here");
|
||||
return false;
|
||||
},
|
||||
},
|
||||
AssocItem::Const(it) => it.id.into(),
|
||||
AssocItem::TypeAlias(it) => it.id.into(),
|
||||
};
|
||||
@@ -918,20 +934,15 @@ pub fn diagnostics<'db>(
|
||||
impl_assoc_items_scratch.clear();
|
||||
}
|
||||
|
||||
push_ty_diagnostics(db, acc, db.impl_self_ty_with_diagnostics(impl_id).1, &source_map);
|
||||
push_ty_diagnostics(
|
||||
db,
|
||||
acc,
|
||||
db.impl_self_ty_with_diagnostics(impl_def.id).1,
|
||||
&source_map,
|
||||
);
|
||||
push_ty_diagnostics(
|
||||
db,
|
||||
acc,
|
||||
db.impl_trait_with_diagnostics(impl_def.id).and_then(|it| it.1),
|
||||
db.impl_trait_with_diagnostics(impl_id).and_then(|it| it.1),
|
||||
&source_map,
|
||||
);
|
||||
|
||||
for &(_, item) in impl_def.id.impl_items(db).items.iter() {
|
||||
for &(_, item) in impl_id.impl_items(db).items.iter() {
|
||||
AssocItem::from(item).diagnostics(db, acc, style_lints);
|
||||
}
|
||||
}
|
||||
@@ -955,7 +966,8 @@ pub fn legacy_macros(self, db: &dyn HirDatabase) -> Vec<Macro> {
|
||||
|
||||
pub fn impl_defs(self, db: &dyn HirDatabase) -> Vec<Impl> {
|
||||
let def_map = self.id.def_map(db);
|
||||
def_map[self.id].scope.impls().map(Impl::from).collect()
|
||||
let scope = &def_map[self.id].scope;
|
||||
scope.impls().map(Impl::from).chain(scope.builtin_derive_impls().map(Impl::from)).collect()
|
||||
}
|
||||
|
||||
/// Finds a path that can be used to refer to the given item from within
|
||||
@@ -968,7 +980,7 @@ pub fn find_path(
|
||||
) -> Option<ModPath> {
|
||||
hir_def::find_path::find_path(
|
||||
db,
|
||||
item.into().into(),
|
||||
item.into().try_into().ok()?,
|
||||
self.into(),
|
||||
PrefixKind::Plain,
|
||||
false,
|
||||
@@ -985,7 +997,14 @@ pub fn find_use_path(
|
||||
prefix_kind: PrefixKind,
|
||||
cfg: FindPathConfig,
|
||||
) -> Option<ModPath> {
|
||||
hir_def::find_path::find_path(db, item.into().into(), self.into(), prefix_kind, true, cfg)
|
||||
hir_def::find_path::find_path(
|
||||
db,
|
||||
item.into().try_into().ok()?,
|
||||
self.into(),
|
||||
prefix_kind,
|
||||
true,
|
||||
cfg,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -1863,9 +1882,9 @@ pub fn module(self, db: &dyn HirDatabase) -> Module {
|
||||
|
||||
pub fn name(&self, db: &dyn HirDatabase) -> Name {
|
||||
match self {
|
||||
VariantDef::Struct(s) => s.name(db),
|
||||
VariantDef::Union(u) => u.name(db),
|
||||
VariantDef::Variant(e) => e.name(db),
|
||||
VariantDef::Struct(s) => (*s).name(db),
|
||||
VariantDef::Union(u) => (*u).name(db),
|
||||
VariantDef::Variant(e) => (*e).name(db),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1909,24 +1928,33 @@ pub fn body_type(self, db: &dyn HirDatabase) -> Type<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
fn id(&self) -> DefWithBodyId {
|
||||
match self {
|
||||
DefWithBody::Function(it) => it.id.into(),
|
||||
fn id(&self) -> Option<DefWithBodyId> {
|
||||
Some(match self {
|
||||
DefWithBody::Function(it) => match it.id {
|
||||
AnyFunctionId::FunctionId(id) => id.into(),
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { .. } => return None,
|
||||
},
|
||||
DefWithBody::Static(it) => it.id.into(),
|
||||
DefWithBody::Const(it) => it.id.into(),
|
||||
DefWithBody::Variant(it) => it.into(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// A textual representation of the HIR of this def's body for debugging purposes.
|
||||
pub fn debug_hir(self, db: &dyn HirDatabase) -> String {
|
||||
let body = db.body(self.id());
|
||||
body.pretty_print(db, self.id(), Edition::CURRENT)
|
||||
let Some(id) = self.id() else {
|
||||
return String::new();
|
||||
};
|
||||
let body = db.body(id);
|
||||
body.pretty_print(db, id, Edition::CURRENT)
|
||||
}
|
||||
|
||||
/// A textual representation of the MIR of this def's body for debugging purposes.
|
||||
pub fn debug_mir(self, db: &dyn HirDatabase) -> String {
|
||||
let body = db.mir_body(self.id());
|
||||
let Some(id) = self.id() else {
|
||||
return String::new();
|
||||
};
|
||||
let body = db.mir_body(id);
|
||||
match body {
|
||||
Ok(body) => body.pretty_print(db, self.module(db).krate(db).to_display_target(db)),
|
||||
Err(e) => format!("error:\n{e:?}"),
|
||||
@@ -1939,11 +1967,17 @@ pub fn diagnostics<'db>(
|
||||
acc: &mut Vec<AnyDiagnostic<'db>>,
|
||||
style_lints: bool,
|
||||
) {
|
||||
let Ok(id) = self.try_into() else {
|
||||
return;
|
||||
};
|
||||
let krate = self.module(db).id.krate(db);
|
||||
|
||||
let (body, source_map) = db.body_with_source_map(self.into());
|
||||
let (body, source_map) = db.body_with_source_map(id);
|
||||
let sig_source_map = match self {
|
||||
DefWithBody::Function(id) => db.function_signature_with_source_map(id.into()).1,
|
||||
DefWithBody::Function(id) => match id.id {
|
||||
AnyFunctionId::FunctionId(id) => db.function_signature_with_source_map(id).1,
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { .. } => return,
|
||||
},
|
||||
DefWithBody::Static(id) => db.static_signature_with_source_map(id.into()).1,
|
||||
DefWithBody::Const(id) => db.const_signature_with_source_map(id.into()).1,
|
||||
DefWithBody::Variant(variant) => {
|
||||
@@ -1958,11 +1992,11 @@ pub fn diagnostics<'db>(
|
||||
|
||||
expr_store_diagnostics(db, acc, &source_map);
|
||||
|
||||
let infer = InferenceResult::for_body(db, self.into());
|
||||
let infer = InferenceResult::for_body(db, id);
|
||||
for d in infer.diagnostics() {
|
||||
acc.extend(AnyDiagnostic::inference_diagnostic(
|
||||
db,
|
||||
self.into(),
|
||||
id,
|
||||
d,
|
||||
&source_map,
|
||||
&sig_source_map,
|
||||
@@ -1989,14 +2023,14 @@ pub fn diagnostics<'db>(
|
||||
acc.push(
|
||||
TypeMismatch {
|
||||
expr_or_pat,
|
||||
expected: Type::new(db, DefWithBodyId::from(self), mismatch.expected.as_ref()),
|
||||
actual: Type::new(db, DefWithBodyId::from(self), mismatch.actual.as_ref()),
|
||||
expected: Type::new(db, id, mismatch.expected.as_ref()),
|
||||
actual: Type::new(db, id, mismatch.actual.as_ref()),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
let missing_unsafe = hir_ty::diagnostics::missing_unsafe(db, self.into());
|
||||
let missing_unsafe = hir_ty::diagnostics::missing_unsafe(db, id);
|
||||
for (node, reason) in missing_unsafe.unsafe_exprs {
|
||||
match source_map.expr_or_pat_syntax(node) {
|
||||
Ok(node) => acc.push(
|
||||
@@ -2031,7 +2065,7 @@ pub fn diagnostics<'db>(
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(borrowck_results) = db.borrowck(self.into()) {
|
||||
if let Ok(borrowck_results) = db.borrowck(id) {
|
||||
for borrowck_result in borrowck_results.iter() {
|
||||
let mir_body = &borrowck_result.mir_body;
|
||||
for moof in &borrowck_result.moved_out_of_ref {
|
||||
@@ -2088,7 +2122,7 @@ pub fn diagnostics<'db>(
|
||||
{
|
||||
need_mut = &mir::MutabilityReason::Not;
|
||||
}
|
||||
let local = Local { parent: self.into(), binding_id };
|
||||
let local = Local { parent: id, binding_id };
|
||||
let is_mut = body[binding_id].mode == BindingAnnotation::Mutable;
|
||||
|
||||
match (need_mut, is_mut) {
|
||||
@@ -2144,17 +2178,11 @@ pub fn diagnostics<'db>(
|
||||
}
|
||||
}
|
||||
|
||||
for diagnostic in BodyValidationDiagnostic::collect(db, self.into(), style_lints) {
|
||||
for diagnostic in BodyValidationDiagnostic::collect(db, id, style_lints) {
|
||||
acc.extend(AnyDiagnostic::body_validation_diagnostic(db, diagnostic, &source_map));
|
||||
}
|
||||
|
||||
let def: ModuleDef = match self {
|
||||
DefWithBody::Function(it) => it.into(),
|
||||
DefWithBody::Static(it) => it.into(),
|
||||
DefWithBody::Const(it) => it.into(),
|
||||
DefWithBody::Variant(it) => it.into(),
|
||||
};
|
||||
for diag in hir_ty::diagnostics::incorrect_case(db, def.into()) {
|
||||
for diag in hir_ty::diagnostics::incorrect_case(db, id.into()) {
|
||||
acc.push(diag.into())
|
||||
}
|
||||
}
|
||||
@@ -2192,45 +2220,181 @@ fn expr_store_diagnostics<'db>(
|
||||
.macro_calls()
|
||||
.for_each(|(_ast_id, call_id)| macro_call_diagnostics(db, call_id, acc));
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
enum AnyFunctionId {
|
||||
FunctionId(FunctionId),
|
||||
BuiltinDeriveImplMethod { method: BuiltinDeriveImplMethod, impl_: BuiltinDeriveImplId },
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct Function {
|
||||
pub(crate) id: FunctionId,
|
||||
pub(crate) id: AnyFunctionId,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Function {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.id, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Function {
|
||||
pub fn module(self, db: &dyn HirDatabase) -> Module {
|
||||
self.id.module(db).into()
|
||||
match self.id {
|
||||
AnyFunctionId::FunctionId(id) => id.module(db).into(),
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { impl_, .. } => impl_.module(db).into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(self, db: &dyn HirDatabase) -> Name {
|
||||
db.function_signature(self.id).name.clone()
|
||||
match self.id {
|
||||
AnyFunctionId::FunctionId(id) => db.function_signature(id).name.clone(),
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { method, .. } => {
|
||||
Name::new_symbol_root(method.name())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> {
|
||||
Type::from_value_def(db, self.id)
|
||||
match self.id {
|
||||
AnyFunctionId::FunctionId(id) => Type::from_value_def(db, id),
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } => {
|
||||
// Get the type for the trait function, as we can't get the type for the impl function
|
||||
// because it has not `CallableDefId`.
|
||||
let krate = impl_.module(db).krate(db);
|
||||
let interner = DbInterner::new_with(db, krate);
|
||||
let param_env = hir_ty::builtin_derive::param_env(interner, impl_);
|
||||
let env = ParamEnvAndCrate { param_env, krate };
|
||||
let Some(trait_method) = method.trait_method(db, impl_) else {
|
||||
return Type { env, ty: Ty::new_error(interner, ErrorGuaranteed) };
|
||||
};
|
||||
Function::from(trait_method).ty(db)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fn_ptr_type(self, db: &dyn HirDatabase) -> Type<'_> {
|
||||
let resolver = self.id.resolver(db);
|
||||
let interner = DbInterner::new_no_crate(db);
|
||||
// FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s.
|
||||
let callable_sig = db.callable_item_signature(self.id.into()).instantiate_identity();
|
||||
let ty = Ty::new_fn_ptr(interner, callable_sig);
|
||||
Type::new_with_resolver_inner(db, &resolver, ty)
|
||||
match self.id {
|
||||
AnyFunctionId::FunctionId(id) => {
|
||||
let resolver = id.resolver(db);
|
||||
let interner = DbInterner::new_no_crate(db);
|
||||
// FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s.
|
||||
let callable_sig = db.callable_item_signature(id.into()).instantiate_identity();
|
||||
let ty = Ty::new_fn_ptr(interner, callable_sig);
|
||||
Type::new_with_resolver_inner(db, &resolver, ty)
|
||||
}
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } => {
|
||||
struct ParamsShifter<'db> {
|
||||
interner: DbInterner<'db>,
|
||||
shift_by: i32,
|
||||
}
|
||||
|
||||
impl<'db> TypeFolder<DbInterner<'db>> for ParamsShifter<'db> {
|
||||
fn cx(&self) -> DbInterner<'db> {
|
||||
self.interner
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'db>) -> Ty<'db> {
|
||||
if let TyKind::Param(param) = ty.kind() {
|
||||
Ty::new_param(
|
||||
self.interner,
|
||||
param.id,
|
||||
param.index.checked_add_signed(self.shift_by).unwrap(),
|
||||
)
|
||||
} else {
|
||||
ty.super_fold_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_const(
|
||||
&mut self,
|
||||
ct: hir_ty::next_solver::Const<'db>,
|
||||
) -> hir_ty::next_solver::Const<'db> {
|
||||
if let ConstKind::Param(param) = ct.kind() {
|
||||
hir_ty::next_solver::Const::new_param(
|
||||
self.interner,
|
||||
ParamConst {
|
||||
id: param.id,
|
||||
index: param.index.checked_add_signed(self.shift_by).unwrap(),
|
||||
},
|
||||
)
|
||||
} else {
|
||||
ct.super_fold_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
|
||||
if let RegionKind::ReEarlyParam(param) = r.kind() {
|
||||
Region::new_early_param(
|
||||
self.interner,
|
||||
EarlyParamRegion {
|
||||
id: param.id,
|
||||
index: param.index.checked_add_signed(self.shift_by).unwrap(),
|
||||
},
|
||||
)
|
||||
} else {
|
||||
r
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the type for the trait function, as we can't get the type for the impl function
|
||||
// because it has not `CallableDefId`.
|
||||
let krate = impl_.module(db).krate(db);
|
||||
let interner = DbInterner::new_with(db, krate);
|
||||
let param_env = hir_ty::builtin_derive::param_env(interner, impl_);
|
||||
let env = ParamEnvAndCrate { param_env, krate };
|
||||
let Some(trait_method) = method.trait_method(db, impl_) else {
|
||||
return Type { env, ty: Ty::new_error(interner, ErrorGuaranteed) };
|
||||
};
|
||||
// The procedure works as follows: the method may have additional generic parameters (e.g. `Hash::hash()`),
|
||||
// and we want them to be params of the impl method as well. So we start with the trait method identity
|
||||
// args and extract from them the trait method own args. In parallel, we retrieve the impl trait ref.
|
||||
// Now we can put our args as [...impl_trait_ref.args, ...trait_method_own_args], but we have one problem:
|
||||
// the args in `trait_method_own_args` use indices appropriate for the trait method, which are not necessarily
|
||||
// good for the impl method. So we shift them by `impl_generics_len - trait_generics_len`, which is essentially
|
||||
// `impl_generics_len - impl_trait_ref.args.len()`.
|
||||
let trait_method_fn_ptr = Ty::new_fn_ptr(
|
||||
interner,
|
||||
db.callable_item_signature(trait_method.into()).instantiate_identity(),
|
||||
);
|
||||
let impl_trait_ref =
|
||||
hir_ty::builtin_derive::impl_trait(interner, impl_).instantiate_identity();
|
||||
let trait_method_args =
|
||||
GenericArgs::identity_for_item(interner, trait_method.into());
|
||||
let trait_method_own_args = GenericArgs::new_from_iter(
|
||||
interner,
|
||||
trait_method_args.iter().skip(impl_trait_ref.args.len()),
|
||||
);
|
||||
let impl_params_count = hir_ty::builtin_derive::generic_params_count(db, impl_);
|
||||
let shift_args_by = impl_params_count as i32 - impl_trait_ref.args.len() as i32;
|
||||
let shifted_trait_method_own_args = trait_method_own_args
|
||||
.fold_with(&mut ParamsShifter { interner, shift_by: shift_args_by });
|
||||
let impl_method_args = GenericArgs::new_from_iter(
|
||||
interner,
|
||||
impl_trait_ref.args.iter().chain(shifted_trait_method_own_args),
|
||||
);
|
||||
let impl_method_fn_ptr =
|
||||
EarlyBinder::bind(trait_method_fn_ptr).instantiate(interner, impl_method_args);
|
||||
Type { env, ty: impl_method_fn_ptr }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fn_sig<'db>(self, db: &'db dyn HirDatabase) -> (ParamEnvAndCrate<'db>, PolyFnSig<'db>) {
|
||||
let fn_ptr = self.fn_ptr_type(db);
|
||||
let TyKind::FnPtr(sig_tys, hdr) = fn_ptr.ty.kind() else {
|
||||
unreachable!();
|
||||
};
|
||||
(fn_ptr.env, sig_tys.with(hdr))
|
||||
}
|
||||
|
||||
// FIXME: Find a better API to express all combinations here, perhaps we should have `PreInstantiationType`?
|
||||
|
||||
/// Get this function's return type
|
||||
pub fn ret_type(self, db: &dyn HirDatabase) -> Type<'_> {
|
||||
let resolver = self.id.resolver(db);
|
||||
// FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s.
|
||||
let ty = db
|
||||
.callable_item_signature(self.id.into())
|
||||
.instantiate_identity()
|
||||
.skip_binder()
|
||||
.output();
|
||||
Type::new_with_resolver_inner(db, &resolver, ty)
|
||||
let (env, sig) = self.fn_sig(db);
|
||||
Type { env, ty: sig.skip_binder().output() }
|
||||
}
|
||||
|
||||
// FIXME: Find better API to also handle const generics
|
||||
@@ -2239,30 +2403,41 @@ pub fn ret_type_with_args<'db>(
|
||||
db: &'db dyn HirDatabase,
|
||||
generics: impl Iterator<Item = Type<'db>>,
|
||||
) -> Type<'db> {
|
||||
let resolver = self.id.resolver(db);
|
||||
let ret_type = self.ret_type(db);
|
||||
let interner = DbInterner::new_no_crate(db);
|
||||
let args = generic_args_from_tys(interner, self.id.into(), generics.map(|ty| ty.ty));
|
||||
let args = self.adapt_generic_args(interner, generics);
|
||||
ret_type.derived(EarlyBinder::bind(ret_type.ty).instantiate(interner, args))
|
||||
}
|
||||
|
||||
let interner = DbInterner::new_no_crate(db);
|
||||
let ty = db
|
||||
.callable_item_signature(self.id.into())
|
||||
.instantiate(interner, args)
|
||||
.skip_binder()
|
||||
.output();
|
||||
Type::new_with_resolver_inner(db, &resolver, ty)
|
||||
fn adapt_generic_args<'db>(
|
||||
self,
|
||||
interner: DbInterner<'db>,
|
||||
generics: impl Iterator<Item = Type<'db>>,
|
||||
) -> GenericArgs<'db> {
|
||||
let generics = generics.map(|ty| ty.ty);
|
||||
match self.id {
|
||||
AnyFunctionId::FunctionId(id) => generic_args_from_tys(interner, id.into(), generics),
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { impl_, .. } => {
|
||||
let impl_args = GenericArgs::identity_for_item(interner, impl_.into());
|
||||
GenericArgs::new_from_iter(
|
||||
interner,
|
||||
impl_args.iter().chain(generics.map(Into::into)),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn async_ret_type<'db>(self, db: &'db dyn HirDatabase) -> Option<Type<'db>> {
|
||||
let AnyFunctionId::FunctionId(id) = self.id else {
|
||||
return None;
|
||||
};
|
||||
if !self.is_async(db) {
|
||||
return None;
|
||||
}
|
||||
let resolver = self.id.resolver(db);
|
||||
let resolver = id.resolver(db);
|
||||
// FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s.
|
||||
let ret_ty = db
|
||||
.callable_item_signature(self.id.into())
|
||||
.instantiate_identity()
|
||||
.skip_binder()
|
||||
.output();
|
||||
let ret_ty =
|
||||
db.callable_item_signature(id.into()).instantiate_identity().skip_binder().output();
|
||||
for pred in ret_ty.impl_trait_bounds(db).into_iter().flatten() {
|
||||
if let ClauseKind::Projection(projection) = pred.kind().skip_binder()
|
||||
&& let Some(output_ty) = projection.term.as_type()
|
||||
@@ -2274,31 +2449,47 @@ pub fn async_ret_type<'db>(self, db: &'db dyn HirDatabase) -> Option<Type<'db>>
|
||||
}
|
||||
|
||||
pub fn has_self_param(self, db: &dyn HirDatabase) -> bool {
|
||||
db.function_signature(self.id).has_self_param()
|
||||
match self.id {
|
||||
AnyFunctionId::FunctionId(id) => db.function_signature(id).has_self_param(),
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { method, .. } => match method {
|
||||
BuiltinDeriveImplMethod::clone
|
||||
| BuiltinDeriveImplMethod::fmt
|
||||
| BuiltinDeriveImplMethod::hash
|
||||
| BuiltinDeriveImplMethod::cmp
|
||||
| BuiltinDeriveImplMethod::partial_cmp
|
||||
| BuiltinDeriveImplMethod::eq => true,
|
||||
BuiltinDeriveImplMethod::default => false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> {
|
||||
self.has_self_param(db).then_some(SelfParam { func: self.id })
|
||||
self.has_self_param(db).then_some(SelfParam { func: self })
|
||||
}
|
||||
|
||||
pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec<Param<'_>> {
|
||||
let environment = param_env_from_has_crate(db, self.id);
|
||||
// FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s.
|
||||
let callable_sig =
|
||||
db.callable_item_signature(self.id.into()).instantiate_identity().skip_binder();
|
||||
callable_sig
|
||||
let (env, sig) = self.fn_sig(db);
|
||||
let func = match self.id {
|
||||
AnyFunctionId::FunctionId(id) => Callee::Def(CallableDefId::FunctionId(id)),
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } => {
|
||||
Callee::BuiltinDeriveImplMethod { method, impl_ }
|
||||
}
|
||||
};
|
||||
sig.skip_binder()
|
||||
.inputs()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, &ty)| {
|
||||
let ty = Type { env: environment, ty };
|
||||
Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx }
|
||||
})
|
||||
.map(|(idx, &ty)| Param { func: func.clone(), ty: Type { env, ty }, idx })
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn num_params(self, db: &dyn HirDatabase) -> usize {
|
||||
db.function_signature(self.id).params.len()
|
||||
match self.id {
|
||||
AnyFunctionId::FunctionId(id) => db.function_signature(id).params.len(),
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { .. } => {
|
||||
self.fn_sig(db).1.skip_binder().inputs().len()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn method_params(self, db: &dyn HirDatabase) -> Option<Vec<Param<'_>>> {
|
||||
@@ -2307,21 +2498,11 @@ pub fn method_params(self, db: &dyn HirDatabase) -> Option<Vec<Param<'_>>> {
|
||||
}
|
||||
|
||||
pub fn params_without_self(self, db: &dyn HirDatabase) -> Vec<Param<'_>> {
|
||||
let environment = param_env_from_has_crate(db, self.id);
|
||||
// FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s.
|
||||
let callable_sig =
|
||||
db.callable_item_signature(self.id.into()).instantiate_identity().skip_binder();
|
||||
let skip = if db.function_signature(self.id).has_self_param() { 1 } else { 0 };
|
||||
callable_sig
|
||||
.inputs()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.skip(skip)
|
||||
.map(|(idx, &ty)| {
|
||||
let ty = Type { env: environment, ty };
|
||||
Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx }
|
||||
})
|
||||
.collect()
|
||||
let mut params = self.assoc_fn_params(db);
|
||||
if self.has_self_param(db) {
|
||||
params.remove(0);
|
||||
}
|
||||
params
|
||||
}
|
||||
|
||||
// FIXME: Find better API to also handle const generics
|
||||
@@ -2330,40 +2511,50 @@ pub fn params_without_self_with_args<'db>(
|
||||
db: &'db dyn HirDatabase,
|
||||
generics: impl Iterator<Item = Type<'db>>,
|
||||
) -> Vec<Param<'db>> {
|
||||
let environment = param_env_from_has_crate(db, self.id);
|
||||
let interner = DbInterner::new_no_crate(db);
|
||||
let args = generic_args_from_tys(interner, self.id.into(), generics.map(|ty| ty.ty));
|
||||
let callable_sig =
|
||||
db.callable_item_signature(self.id.into()).instantiate(interner, args).skip_binder();
|
||||
let skip = if db.function_signature(self.id).has_self_param() { 1 } else { 0 };
|
||||
callable_sig
|
||||
.inputs()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.skip(skip)
|
||||
.map(|(idx, &ty)| {
|
||||
let ty = Type { env: environment, ty };
|
||||
Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx }
|
||||
let args = self.adapt_generic_args(interner, generics);
|
||||
let params = self.params_without_self(db);
|
||||
params
|
||||
.into_iter()
|
||||
.map(|param| Param {
|
||||
func: param.func,
|
||||
idx: param.idx,
|
||||
ty: Type {
|
||||
env: param.ty.env,
|
||||
ty: EarlyBinder::bind(param.ty.ty).instantiate(interner, args),
|
||||
},
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn is_const(self, db: &dyn HirDatabase) -> bool {
|
||||
db.function_signature(self.id).is_const()
|
||||
match self.id {
|
||||
AnyFunctionId::FunctionId(id) => db.function_signature(id).is_const(),
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { .. } => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_async(self, db: &dyn HirDatabase) -> bool {
|
||||
db.function_signature(self.id).is_async()
|
||||
match self.id {
|
||||
AnyFunctionId::FunctionId(id) => db.function_signature(id).is_async(),
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { .. } => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_varargs(self, db: &dyn HirDatabase) -> bool {
|
||||
db.function_signature(self.id).is_varargs()
|
||||
match self.id {
|
||||
AnyFunctionId::FunctionId(id) => db.function_signature(id).is_varargs(),
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { .. } => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extern_block(self, db: &dyn HirDatabase) -> Option<ExternBlock> {
|
||||
match self.id.lookup(db).container {
|
||||
ItemContainerId::ExternBlockId(id) => Some(ExternBlock { id }),
|
||||
_ => None,
|
||||
match self.id {
|
||||
AnyFunctionId::FunctionId(id) => match id.lookup(db).container {
|
||||
ItemContainerId::ExternBlockId(id) => Some(ExternBlock { id }),
|
||||
_ => None,
|
||||
},
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { .. } => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2396,33 +2587,46 @@ pub fn returns_impl_future(self, db: &dyn HirDatabase) -> bool {
|
||||
|
||||
/// Does this function have `#[test]` attribute?
|
||||
pub fn is_test(self, db: &dyn HirDatabase) -> bool {
|
||||
self.attrs(db).is_test()
|
||||
self.attrs(db).contains(AttrFlags::IS_TEST)
|
||||
}
|
||||
|
||||
/// is this a `fn main` or a function with an `export_name` of `main`?
|
||||
pub fn is_main(self, db: &dyn HirDatabase) -> bool {
|
||||
self.exported_main(db)
|
||||
|| self.module(db).is_crate_root(db) && db.function_signature(self.id).name == sym::main
|
||||
match self.id {
|
||||
AnyFunctionId::FunctionId(id) => {
|
||||
self.exported_main(db)
|
||||
|| self.module(db).is_crate_root(db)
|
||||
&& db.function_signature(id).name == sym::main
|
||||
}
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { .. } => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn attrs(self, db: &dyn HirDatabase) -> AttrFlags {
|
||||
match self.id {
|
||||
AnyFunctionId::FunctionId(id) => AttrFlags::query(db, id.into()),
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { .. } => AttrFlags::empty(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Is this a function with an `export_name` of `main`?
|
||||
pub fn exported_main(self, db: &dyn HirDatabase) -> bool {
|
||||
AttrFlags::query(db, self.id.into()).contains(AttrFlags::IS_EXPORT_NAME_MAIN)
|
||||
self.attrs(db).contains(AttrFlags::IS_EXPORT_NAME_MAIN)
|
||||
}
|
||||
|
||||
/// Does this function have the ignore attribute?
|
||||
pub fn is_ignore(self, db: &dyn HirDatabase) -> bool {
|
||||
AttrFlags::query(db, self.id.into()).contains(AttrFlags::IS_IGNORE)
|
||||
self.attrs(db).contains(AttrFlags::IS_IGNORE)
|
||||
}
|
||||
|
||||
/// Does this function have `#[bench]` attribute?
|
||||
pub fn is_bench(self, db: &dyn HirDatabase) -> bool {
|
||||
AttrFlags::query(db, self.id.into()).contains(AttrFlags::IS_BENCH)
|
||||
self.attrs(db).contains(AttrFlags::IS_BENCH)
|
||||
}
|
||||
|
||||
/// Is this function marked as unstable with `#[feature]` attribute?
|
||||
pub fn is_unstable(self, db: &dyn HirDatabase) -> bool {
|
||||
AttrFlags::query(db, self.id.into()).contains(AttrFlags::IS_UNSTABLE)
|
||||
self.attrs(db).contains(AttrFlags::IS_UNSTABLE)
|
||||
}
|
||||
|
||||
pub fn is_unsafe_to_call(
|
||||
@@ -2431,9 +2635,17 @@ pub fn is_unsafe_to_call(
|
||||
caller: Option<Function>,
|
||||
call_edition: Edition,
|
||||
) -> bool {
|
||||
let AnyFunctionId::FunctionId(id) = self.id else {
|
||||
return false;
|
||||
};
|
||||
let (target_features, target_feature_is_safe_in_target) = caller
|
||||
.map(|caller| {
|
||||
let target_features = hir_ty::TargetFeatures::from_fn(db, caller.id);
|
||||
let target_features = match caller.id {
|
||||
AnyFunctionId::FunctionId(id) => hir_ty::TargetFeatures::from_fn(db, id),
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { .. } => {
|
||||
hir_ty::TargetFeatures::default()
|
||||
}
|
||||
};
|
||||
let target_feature_is_safe_in_target =
|
||||
match &caller.krate(db).id.workspace_data(db).target {
|
||||
Ok(target) => hir_ty::target_feature_is_safe_in_target(target),
|
||||
@@ -2447,7 +2659,7 @@ pub fn is_unsafe_to_call(
|
||||
matches!(
|
||||
hir_ty::is_fn_unsafe_to_call(
|
||||
db,
|
||||
self.id,
|
||||
id,
|
||||
&target_features,
|
||||
call_edition,
|
||||
target_feature_is_safe_in_target
|
||||
@@ -2460,12 +2672,18 @@ pub fn is_unsafe_to_call(
|
||||
///
|
||||
/// This is false in the case of required (not provided) trait methods.
|
||||
pub fn has_body(self, db: &dyn HirDatabase) -> bool {
|
||||
db.function_signature(self.id).has_body()
|
||||
match self.id {
|
||||
AnyFunctionId::FunctionId(id) => db.function_signature(id).has_body(),
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { .. } => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_proc_macro(self, db: &dyn HirDatabase) -> Option<Macro> {
|
||||
let def_map = crate_def_map(db, HasModule::krate(&self.id, db));
|
||||
def_map.fn_as_proc_macro(self.id).map(|id| Macro { id: id.into() })
|
||||
let AnyFunctionId::FunctionId(id) = self.id else {
|
||||
return None;
|
||||
};
|
||||
let def_map = crate_def_map(db, HasModule::krate(&id, db));
|
||||
def_map.fn_as_proc_macro(id).map(|id| Macro { id: id.into() })
|
||||
}
|
||||
|
||||
pub fn eval(
|
||||
@@ -2473,13 +2691,18 @@ pub fn eval(
|
||||
db: &dyn HirDatabase,
|
||||
span_formatter: impl Fn(FileId, TextRange) -> String,
|
||||
) -> Result<String, ConstEvalError> {
|
||||
let AnyFunctionId::FunctionId(id) = self.id else {
|
||||
return Err(ConstEvalError::MirEvalError(MirEvalError::NotSupported(
|
||||
"evaluation of builtin derive impl methods is not supported".to_owned(),
|
||||
)));
|
||||
};
|
||||
let interner = DbInterner::new_no_crate(db);
|
||||
let body = db.monomorphized_mir_body(
|
||||
self.id.into(),
|
||||
id.into(),
|
||||
GenericArgs::empty(interner).store(),
|
||||
ParamEnvAndCrate {
|
||||
param_env: db.trait_environment(self.id.into()),
|
||||
krate: self.id.module(db).krate(db),
|
||||
param_env: db.trait_environment(id.into()),
|
||||
krate: id.module(db).krate(db),
|
||||
}
|
||||
.store(),
|
||||
)?;
|
||||
@@ -2596,36 +2819,47 @@ pub fn pattern_source(self, db: &dyn HirDatabase) -> Option<ast::Pat> {
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct SelfParam {
|
||||
func: FunctionId,
|
||||
func: Function,
|
||||
}
|
||||
|
||||
impl SelfParam {
|
||||
pub fn access(self, db: &dyn HirDatabase) -> Access {
|
||||
let func_data = db.function_signature(self.func);
|
||||
func_data
|
||||
.params
|
||||
.first()
|
||||
.map(|¶m| match &func_data.store[param] {
|
||||
TypeRef::Reference(ref_) => match ref_.mutability {
|
||||
hir_def::type_ref::Mutability::Shared => Access::Shared,
|
||||
hir_def::type_ref::Mutability::Mut => Access::Exclusive,
|
||||
},
|
||||
_ => Access::Owned,
|
||||
})
|
||||
.unwrap_or(Access::Owned)
|
||||
match self.func.id {
|
||||
AnyFunctionId::FunctionId(id) => {
|
||||
let func_data = db.function_signature(id);
|
||||
func_data
|
||||
.params
|
||||
.first()
|
||||
.map(|¶m| match &func_data.store[param] {
|
||||
TypeRef::Reference(ref_) => match ref_.mutability {
|
||||
hir_def::type_ref::Mutability::Shared => Access::Shared,
|
||||
hir_def::type_ref::Mutability::Mut => Access::Exclusive,
|
||||
},
|
||||
_ => Access::Owned,
|
||||
})
|
||||
.unwrap_or(Access::Owned)
|
||||
}
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { method, .. } => match method {
|
||||
BuiltinDeriveImplMethod::clone
|
||||
| BuiltinDeriveImplMethod::fmt
|
||||
| BuiltinDeriveImplMethod::hash
|
||||
| BuiltinDeriveImplMethod::cmp
|
||||
| BuiltinDeriveImplMethod::partial_cmp
|
||||
| BuiltinDeriveImplMethod::eq => Access::Shared,
|
||||
BuiltinDeriveImplMethod::default => {
|
||||
unreachable!("this function does not have a self param")
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parent_fn(&self) -> Function {
|
||||
Function::from(self.func)
|
||||
self.func
|
||||
}
|
||||
|
||||
pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> {
|
||||
// FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s.
|
||||
let callable_sig =
|
||||
db.callable_item_signature(self.func.into()).instantiate_identity().skip_binder();
|
||||
let environment = param_env_from_has_crate(db, self.func);
|
||||
let ty = rustc_type_ir::inherent::SliceLike::as_slice(&callable_sig.inputs())[0];
|
||||
Type { env: environment, ty }
|
||||
let (env, sig) = self.func.fn_sig(db);
|
||||
Type { env, ty: sig.skip_binder().inputs()[0] }
|
||||
}
|
||||
|
||||
// FIXME: Find better API to also handle const generics
|
||||
@@ -2635,18 +2869,18 @@ pub fn ty_with_args<'db>(
|
||||
generics: impl Iterator<Item = Type<'db>>,
|
||||
) -> Type<'db> {
|
||||
let interner = DbInterner::new_no_crate(db);
|
||||
let args = generic_args_from_tys(interner, self.func.into(), generics.map(|ty| ty.ty));
|
||||
let callable_sig =
|
||||
db.callable_item_signature(self.func.into()).instantiate(interner, args).skip_binder();
|
||||
let environment = param_env_from_has_crate(db, self.func);
|
||||
let ty = rustc_type_ir::inherent::SliceLike::as_slice(&callable_sig.inputs())[0];
|
||||
Type { env: environment, ty }
|
||||
let args = self.func.adapt_generic_args(interner, generics);
|
||||
let Type { env, ty } = self.ty(db);
|
||||
Type { env, ty: EarlyBinder::bind(ty).instantiate(interner, args) }
|
||||
}
|
||||
}
|
||||
|
||||
impl HasVisibility for Function {
|
||||
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
|
||||
db.assoc_visibility(self.id.into())
|
||||
match self.id {
|
||||
AnyFunctionId::FunctionId(id) => db.assoc_visibility(id.into()),
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { .. } => Visibility::Public,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2870,7 +3104,7 @@ pub fn all_supertraits(self, db: &dyn HirDatabase) -> Vec<Trait> {
|
||||
pub fn function(self, db: &dyn HirDatabase, name: impl PartialEq<Name>) -> Option<Function> {
|
||||
self.id.trait_items(db).items.iter().find(|(n, _)| name == *n).and_then(|&(_, it)| match it
|
||||
{
|
||||
AssocItemId::FunctionId(id) => Some(Function { id }),
|
||||
AssocItemId::FunctionId(id) => Some(id.into()),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
@@ -3151,15 +3385,15 @@ pub fn is_fn_like(&self, db: &dyn HirDatabase) -> bool {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn is_builtin_derive(&self, db: &dyn HirDatabase) -> bool {
|
||||
match self.id {
|
||||
MacroId::Macro2Id(it) => {
|
||||
matches!(it.lookup(db).expander, MacroExpander::BuiltInDerive(_))
|
||||
}
|
||||
MacroId::MacroRulesId(it) => {
|
||||
matches!(it.lookup(db).expander, MacroExpander::BuiltInDerive(_))
|
||||
}
|
||||
MacroId::ProcMacroId(_) => false,
|
||||
pub fn builtin_derive_kind(&self, db: &dyn HirDatabase) -> Option<BuiltinDeriveMacroKind> {
|
||||
let expander = match self.id {
|
||||
MacroId::Macro2Id(it) => it.lookup(db).expander,
|
||||
MacroId::MacroRulesId(it) => it.lookup(db).expander,
|
||||
MacroId::ProcMacroId(_) => return None,
|
||||
};
|
||||
match expander {
|
||||
MacroExpander::BuiltInDerive(kind) => Some(BuiltinDeriveMacroKind(kind)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3197,6 +3431,9 @@ pub fn is_derive(&self, db: &dyn HirDatabase) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct BuiltinDeriveMacroKind(BuiltinDeriveExpander);
|
||||
|
||||
impl HasVisibility for Macro {
|
||||
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
|
||||
match self.id {
|
||||
@@ -3275,7 +3512,10 @@ pub trait AsExternAssocItem {
|
||||
|
||||
impl AsExternAssocItem for Function {
|
||||
fn as_extern_assoc_item(self, db: &dyn HirDatabase) -> Option<ExternAssocItem> {
|
||||
as_extern_assoc_item(db, ExternAssocItem::Function, self.id)
|
||||
let AnyFunctionId::FunctionId(id) = self.id else {
|
||||
return None;
|
||||
};
|
||||
as_extern_assoc_item(db, ExternAssocItem::Function, id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3303,7 +3543,7 @@ pub enum AssocItem {
|
||||
impl From<method_resolution::CandidateId> for AssocItem {
|
||||
fn from(value: method_resolution::CandidateId) -> Self {
|
||||
match value {
|
||||
method_resolution::CandidateId::FunctionId(id) => AssocItem::Function(Function { id }),
|
||||
method_resolution::CandidateId::FunctionId(id) => AssocItem::Function(id.into()),
|
||||
method_resolution::CandidateId::ConstId(id) => AssocItem::Const(Const { id }),
|
||||
}
|
||||
}
|
||||
@@ -3321,7 +3561,10 @@ pub trait AsAssocItem {
|
||||
|
||||
impl AsAssocItem for Function {
|
||||
fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
|
||||
as_assoc_item(db, AssocItem::Function, self.id)
|
||||
match self.id {
|
||||
AnyFunctionId::FunctionId(id) => as_assoc_item(db, AssocItem::Function, id),
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { .. } => Some(AssocItem::Function(self)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3450,7 +3693,14 @@ pub fn module(self, db: &dyn HirDatabase) -> Module {
|
||||
|
||||
pub fn container(self, db: &dyn HirDatabase) -> AssocItemContainer {
|
||||
let container = match self {
|
||||
AssocItem::Function(it) => it.id.lookup(db).container,
|
||||
AssocItem::Function(it) => match it.id {
|
||||
AnyFunctionId::FunctionId(id) => id.lookup(db).container,
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { impl_, .. } => {
|
||||
return AssocItemContainer::Impl(Impl {
|
||||
id: AnyImplId::BuiltinDeriveImplId(impl_),
|
||||
});
|
||||
}
|
||||
},
|
||||
AssocItem::Const(it) => it.id.lookup(db).container,
|
||||
AssocItem::TypeAlias(it) => it.id.lookup(db).container,
|
||||
};
|
||||
@@ -3587,9 +3837,13 @@ pub enum GenericDef {
|
||||
|
||||
impl GenericDef {
|
||||
pub fn params(self, db: &dyn HirDatabase) -> Vec<GenericParam> {
|
||||
let generics = db.generic_params(self.into());
|
||||
let Ok(id) = self.try_into() else {
|
||||
// Let's pretend builtin derive impls don't have generic parameters.
|
||||
return Vec::new();
|
||||
};
|
||||
let generics = db.generic_params(id);
|
||||
let ty_params = generics.iter_type_or_consts().map(|(local_id, _)| {
|
||||
let toc = TypeOrConstParam { id: TypeOrConstParamId { parent: self.into(), local_id } };
|
||||
let toc = TypeOrConstParam { id: TypeOrConstParamId { parent: id, local_id } };
|
||||
match toc.split(db) {
|
||||
Either::Left(it) => GenericParam::ConstParam(it),
|
||||
Either::Right(it) => GenericParam::TypeParam(it),
|
||||
@@ -3603,39 +3857,51 @@ pub fn params(self, db: &dyn HirDatabase) -> Vec<GenericParam> {
|
||||
}
|
||||
|
||||
pub fn lifetime_params(self, db: &dyn HirDatabase) -> Vec<LifetimeParam> {
|
||||
let generics = db.generic_params(self.into());
|
||||
let Ok(id) = self.try_into() else {
|
||||
// Let's pretend builtin derive impls don't have generic parameters.
|
||||
return Vec::new();
|
||||
};
|
||||
let generics = db.generic_params(id);
|
||||
generics
|
||||
.iter_lt()
|
||||
.map(|(local_id, _)| LifetimeParam {
|
||||
id: LifetimeParamId { parent: self.into(), local_id },
|
||||
})
|
||||
.map(|(local_id, _)| LifetimeParam { id: LifetimeParamId { parent: id, local_id } })
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn type_or_const_params(self, db: &dyn HirDatabase) -> Vec<TypeOrConstParam> {
|
||||
let generics = db.generic_params(self.into());
|
||||
let Ok(id) = self.try_into() else {
|
||||
// Let's pretend builtin derive impls don't have generic parameters.
|
||||
return Vec::new();
|
||||
};
|
||||
let generics = db.generic_params(id);
|
||||
generics
|
||||
.iter_type_or_consts()
|
||||
.map(|(local_id, _)| TypeOrConstParam {
|
||||
id: TypeOrConstParamId { parent: self.into(), local_id },
|
||||
id: TypeOrConstParamId { parent: id, local_id },
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn id(self) -> GenericDefId {
|
||||
match self {
|
||||
GenericDef::Function(it) => it.id.into(),
|
||||
fn id(self) -> Option<GenericDefId> {
|
||||
Some(match self {
|
||||
GenericDef::Function(it) => match it.id {
|
||||
AnyFunctionId::FunctionId(it) => it.into(),
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { .. } => return None,
|
||||
},
|
||||
GenericDef::Adt(it) => it.into(),
|
||||
GenericDef::Trait(it) => it.id.into(),
|
||||
GenericDef::TypeAlias(it) => it.id.into(),
|
||||
GenericDef::Impl(it) => it.id.into(),
|
||||
GenericDef::Impl(it) => match it.id {
|
||||
AnyImplId::ImplId(it) => it.into(),
|
||||
AnyImplId::BuiltinDeriveImplId(_) => return None,
|
||||
},
|
||||
GenericDef::Const(it) => it.id.into(),
|
||||
GenericDef::Static(it) => it.id.into(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn diagnostics<'db>(self, db: &'db dyn HirDatabase, acc: &mut Vec<AnyDiagnostic<'db>>) {
|
||||
let def = self.id();
|
||||
let Some(def) = self.id() else { return };
|
||||
|
||||
let generics = db.generic_params(def);
|
||||
|
||||
@@ -3708,6 +3974,17 @@ fn new(def: GenericDefId, subst: GenericArgs<'db>, env: ParamEnvAndCrate<'db>) -
|
||||
Self { def, subst, env }
|
||||
}
|
||||
|
||||
fn new_from_fn(
|
||||
def: Function,
|
||||
subst: GenericArgs<'db>,
|
||||
env: ParamEnvAndCrate<'db>,
|
||||
) -> Option<Self> {
|
||||
match def.id {
|
||||
AnyFunctionId::FunctionId(def) => Some(Self::new(def.into(), subst, env)),
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { .. } => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn types(&self, db: &'db dyn HirDatabase) -> Vec<(Symbol, Type<'db>)> {
|
||||
let container = match self.def {
|
||||
GenericDefId::ConstId(id) => Some(id.lookup(db).container),
|
||||
@@ -3820,7 +4097,9 @@ pub fn is_param(self, db: &dyn HirDatabase) -> bool {
|
||||
|
||||
pub fn as_self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> {
|
||||
match self.parent {
|
||||
DefWithBodyId::FunctionId(func) if self.is_self(db) => Some(SelfParam { func }),
|
||||
DefWithBodyId::FunctionId(func) if self.is_self(db) => {
|
||||
Some(SelfParam { func: func.into() })
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -4308,7 +4587,7 @@ pub fn as_const_param(self, db: &dyn HirDatabase) -> Option<ConstParam> {
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct Impl {
|
||||
pub(crate) id: ImplId,
|
||||
pub(crate) id: AnyImplId,
|
||||
}
|
||||
|
||||
impl Impl {
|
||||
@@ -4320,6 +4599,7 @@ pub fn all_in_crate(db: &dyn HirDatabase, krate: Crate) -> Vec<Impl> {
|
||||
fn extend_with_def_map(db: &dyn HirDatabase, def_map: &DefMap, result: &mut Vec<Impl>) {
|
||||
for (_, module) in def_map.modules() {
|
||||
result.extend(module.scope.impls().map(Impl::from));
|
||||
result.extend(module.scope.builtin_derive_impls().map(Impl::from));
|
||||
|
||||
for unnamed_const in module.scope.unnamed_consts() {
|
||||
for (_, block_def_map) in db.body(unnamed_const.into()).blocks(db) {
|
||||
@@ -4331,7 +4611,7 @@ fn extend_with_def_map(db: &dyn HirDatabase, def_map: &DefMap, result: &mut Vec<
|
||||
}
|
||||
|
||||
pub fn all_in_module(db: &dyn HirDatabase, module: Module) -> Vec<Impl> {
|
||||
module.id.def_map(db)[module.id].scope.impls().map(Into::into).collect()
|
||||
module.impl_defs(db)
|
||||
}
|
||||
|
||||
/// **Note:** This is an **approximation** that strives to give the *human-perceived notion* of an "impl for type",
|
||||
@@ -4347,20 +4627,19 @@ pub fn all_for_type<'db>(db: &'db dyn HirDatabase, Type { ty, env }: Type<'db>)
|
||||
else {
|
||||
return Vec::new();
|
||||
};
|
||||
let mut extend_with_impls =
|
||||
|impls: &[ImplId]| result.extend(impls.iter().copied().map(Impl::from));
|
||||
method_resolution::with_incoherent_inherent_impls(
|
||||
db,
|
||||
env.krate,
|
||||
&simplified_ty,
|
||||
&mut extend_with_impls,
|
||||
);
|
||||
let mut extend_with_impls = |impls: Either<&[ImplId], &[BuiltinDeriveImplId]>| match impls {
|
||||
Either::Left(impls) => result.extend(impls.iter().copied().map(Impl::from)),
|
||||
Either::Right(impls) => result.extend(impls.iter().copied().map(Impl::from)),
|
||||
};
|
||||
method_resolution::with_incoherent_inherent_impls(db, env.krate, &simplified_ty, |impls| {
|
||||
extend_with_impls(Either::Left(impls))
|
||||
});
|
||||
if let Some(module) = method_resolution::simplified_type_module(db, &simplified_ty) {
|
||||
InherentImpls::for_each_crate_and_block(
|
||||
db,
|
||||
module.krate(db),
|
||||
module.block(db),
|
||||
&mut |impls| extend_with_impls(impls.for_self_ty(&simplified_ty)),
|
||||
&mut |impls| extend_with_impls(Either::Left(impls.for_self_ty(&simplified_ty))),
|
||||
);
|
||||
std::iter::successors(module.block(db), |block| block.loc(db).module.block(db))
|
||||
.filter_map(|block| TraitImpls::for_block(db, block).as_deref())
|
||||
@@ -4382,7 +4661,10 @@ pub fn all_for_trait(db: &dyn HirDatabase, trait_: Trait) -> Vec<Impl> {
|
||||
let module = trait_.module(db).id;
|
||||
let mut all = Vec::new();
|
||||
let mut handle_impls = |impls: &TraitImpls| {
|
||||
impls.for_trait(trait_.id, |impls| all.extend(impls.iter().copied().map(Impl::from)));
|
||||
impls.for_trait(trait_.id, |impls| match impls {
|
||||
Either::Left(impls) => all.extend(impls.iter().copied().map(Impl::from)),
|
||||
Either::Right(impls) => all.extend(impls.iter().copied().map(Impl::from)),
|
||||
});
|
||||
};
|
||||
for krate in module.krate(db).transitive_rev_deps(db) {
|
||||
handle_impls(TraitImpls::for_crate(db, krate));
|
||||
@@ -4396,75 +4678,118 @@ pub fn all_for_trait(db: &dyn HirDatabase, trait_: Trait) -> Vec<Impl> {
|
||||
}
|
||||
|
||||
pub fn trait_(self, db: &dyn HirDatabase) -> Option<Trait> {
|
||||
let trait_ref = db.impl_trait(self.id)?;
|
||||
let id = trait_ref.skip_binder().def_id;
|
||||
Some(Trait { id: id.0 })
|
||||
match self.id {
|
||||
AnyImplId::ImplId(id) => {
|
||||
let trait_ref = db.impl_trait(id)?;
|
||||
let id = trait_ref.skip_binder().def_id;
|
||||
Some(Trait { id: id.0 })
|
||||
}
|
||||
AnyImplId::BuiltinDeriveImplId(id) => {
|
||||
let loc = id.loc(db);
|
||||
let lang_items = hir_def::lang_item::lang_items(db, loc.adt.module(db).krate(db));
|
||||
loc.trait_.get_id(lang_items).map(Trait::from)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trait_ref(self, db: &dyn HirDatabase) -> Option<TraitRef<'_>> {
|
||||
let trait_ref = db.impl_trait(self.id)?.instantiate_identity();
|
||||
let resolver = self.id.resolver(db);
|
||||
Some(TraitRef::new_with_resolver(db, &resolver, trait_ref))
|
||||
match self.id {
|
||||
AnyImplId::ImplId(id) => {
|
||||
let trait_ref = db.impl_trait(id)?.instantiate_identity();
|
||||
let resolver = id.resolver(db);
|
||||
Some(TraitRef::new_with_resolver(db, &resolver, trait_ref))
|
||||
}
|
||||
AnyImplId::BuiltinDeriveImplId(id) => {
|
||||
let loc = id.loc(db);
|
||||
let krate = loc.module(db).krate(db);
|
||||
let interner = DbInterner::new_with(db, krate);
|
||||
let env = ParamEnvAndCrate {
|
||||
param_env: hir_ty::builtin_derive::param_env(interner, id),
|
||||
krate,
|
||||
};
|
||||
let trait_ref =
|
||||
hir_ty::builtin_derive::impl_trait(interner, id).instantiate_identity();
|
||||
Some(TraitRef { env, trait_ref })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn self_ty(self, db: &dyn HirDatabase) -> Type<'_> {
|
||||
let resolver = self.id.resolver(db);
|
||||
// FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s.
|
||||
let ty = db.impl_self_ty(self.id).instantiate_identity();
|
||||
Type::new_with_resolver_inner(db, &resolver, ty)
|
||||
match self.id {
|
||||
AnyImplId::ImplId(id) => {
|
||||
let resolver = id.resolver(db);
|
||||
// FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s.
|
||||
let ty = db.impl_self_ty(id).instantiate_identity();
|
||||
Type::new_with_resolver_inner(db, &resolver, ty)
|
||||
}
|
||||
AnyImplId::BuiltinDeriveImplId(id) => {
|
||||
let loc = id.loc(db);
|
||||
let krate = loc.module(db).krate(db);
|
||||
let interner = DbInterner::new_with(db, krate);
|
||||
let env = ParamEnvAndCrate {
|
||||
param_env: hir_ty::builtin_derive::param_env(interner, id),
|
||||
krate,
|
||||
};
|
||||
let ty = hir_ty::builtin_derive::impl_trait(interner, id)
|
||||
.instantiate_identity()
|
||||
.self_ty();
|
||||
Type { env, ty }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
|
||||
self.id.impl_items(db).items.iter().map(|&(_, it)| it.into()).collect()
|
||||
match self.id {
|
||||
AnyImplId::ImplId(id) => {
|
||||
id.impl_items(db).items.iter().map(|&(_, it)| it.into()).collect()
|
||||
}
|
||||
AnyImplId::BuiltinDeriveImplId(impl_) => impl_
|
||||
.loc(db)
|
||||
.trait_
|
||||
.all_methods()
|
||||
.iter()
|
||||
.map(|&method| {
|
||||
AssocItem::Function(Function {
|
||||
id: AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ },
|
||||
})
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_negative(self, db: &dyn HirDatabase) -> bool {
|
||||
db.impl_signature(self.id).flags.contains(ImplFlags::NEGATIVE)
|
||||
match self.id {
|
||||
AnyImplId::ImplId(id) => db.impl_signature(id).flags.contains(ImplFlags::NEGATIVE),
|
||||
AnyImplId::BuiltinDeriveImplId(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool {
|
||||
db.impl_signature(self.id).flags.contains(ImplFlags::UNSAFE)
|
||||
match self.id {
|
||||
AnyImplId::ImplId(id) => db.impl_signature(id).flags.contains(ImplFlags::UNSAFE),
|
||||
AnyImplId::BuiltinDeriveImplId(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn module(self, db: &dyn HirDatabase) -> Module {
|
||||
self.id.lookup(db).container.into()
|
||||
}
|
||||
|
||||
pub fn as_builtin_derive_path(self, db: &dyn HirDatabase) -> Option<InMacroFile<ast::Path>> {
|
||||
let src = self.source(db)?;
|
||||
|
||||
let macro_file = src.file_id.macro_file()?;
|
||||
let loc = macro_file.lookup(db);
|
||||
let (derive_attr, derive_index) = match loc.kind {
|
||||
MacroCallKind::Derive { ast_id, derive_attr_index, derive_index, .. } => {
|
||||
let module_id = self.id.lookup(db).container;
|
||||
(
|
||||
module_id.def_map(db)[module_id]
|
||||
.scope
|
||||
.derive_macro_invoc(ast_id, derive_attr_index)?,
|
||||
derive_index,
|
||||
)
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
let path = db
|
||||
.parse_macro_expansion(derive_attr)
|
||||
.value
|
||||
.0
|
||||
.syntax_node()
|
||||
.children()
|
||||
.nth(derive_index as usize)
|
||||
.and_then(<ast::Attr as AstNode>::cast)
|
||||
.and_then(|it| it.path())?;
|
||||
Some(InMacroFile { file_id: derive_attr, value: path })
|
||||
match self.id {
|
||||
AnyImplId::ImplId(id) => id.module(db).into(),
|
||||
AnyImplId::BuiltinDeriveImplId(id) => id.module(db).into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_orphan_rules(self, db: &dyn HirDatabase) -> bool {
|
||||
check_orphan_rules(db, self.id)
|
||||
match self.id {
|
||||
AnyImplId::ImplId(id) => check_orphan_rules(db, id),
|
||||
AnyImplId::BuiltinDeriveImplId(_) => true,
|
||||
}
|
||||
}
|
||||
|
||||
fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId<ast::Item>, MacroCallId)]> {
|
||||
self.id.impl_items(db).macro_calls.to_vec().into_boxed_slice()
|
||||
match self.id {
|
||||
AnyImplId::ImplId(id) => id.impl_items(db).macro_calls.to_vec().into_boxed_slice(),
|
||||
AnyImplId::BuiltinDeriveImplId(_) => Box::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5540,7 +5865,7 @@ pub fn iterate_method_candidates_split_inherent(
|
||||
else {
|
||||
unreachable!("`Mode::MethodCall` can only return functions");
|
||||
};
|
||||
let id = Function { id };
|
||||
let id = Function { id: AnyFunctionId::FunctionId(id) };
|
||||
match candidate.kind {
|
||||
method_resolution::PickKind::InherentImplPick(_)
|
||||
| method_resolution::PickKind::ObjectPick(..)
|
||||
@@ -5564,7 +5889,7 @@ pub fn iterate_method_candidates_split_inherent(
|
||||
else {
|
||||
unreachable!("`Mode::MethodCall` can only return functions");
|
||||
};
|
||||
let id = Function { id };
|
||||
let id = Function { id: AnyFunctionId::FunctionId(id) };
|
||||
match candidate.candidate.kind {
|
||||
method_resolution::CandidateKind::InherentImplCandidate {
|
||||
..
|
||||
@@ -5919,6 +6244,7 @@ enum Callee<'db> {
|
||||
CoroutineClosure(InternedCoroutineId, GenericArgs<'db>),
|
||||
FnPtr,
|
||||
FnImpl(traits::FnTrait),
|
||||
BuiltinDeriveImplMethod { method: BuiltinDeriveImplMethod, impl_: BuiltinDeriveImplId },
|
||||
}
|
||||
|
||||
pub enum CallableKind<'db> {
|
||||
@@ -5934,6 +6260,9 @@ impl<'db> Callable<'db> {
|
||||
pub fn kind(&self) -> CallableKind<'db> {
|
||||
match self.callee {
|
||||
Callee::Def(CallableDefId::FunctionId(it)) => CallableKind::Function(it.into()),
|
||||
Callee::BuiltinDeriveImplMethod { method, impl_ } => CallableKind::Function(Function {
|
||||
id: AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ },
|
||||
}),
|
||||
Callee::Def(CallableDefId::StructId(it)) => CallableKind::TupleStruct(it.into()),
|
||||
Callee::Def(CallableDefId::EnumVariantId(it)) => {
|
||||
CallableKind::TupleEnumVariant(it.into())
|
||||
@@ -5948,12 +6277,22 @@ pub fn kind(&self) -> CallableKind<'db> {
|
||||
Callee::FnImpl(fn_) => CallableKind::FnImpl(fn_.into()),
|
||||
}
|
||||
}
|
||||
|
||||
fn as_function(&self) -> Option<Function> {
|
||||
match self.callee {
|
||||
Callee::Def(CallableDefId::FunctionId(it)) => Some(it.into()),
|
||||
Callee::BuiltinDeriveImplMethod { method, impl_ } => {
|
||||
Some(Function { id: AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } })
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn receiver_param(&self, db: &'db dyn HirDatabase) -> Option<(SelfParam, Type<'db>)> {
|
||||
let func = match self.callee {
|
||||
Callee::Def(CallableDefId::FunctionId(it)) if self.is_bound_method => it,
|
||||
_ => return None,
|
||||
};
|
||||
let func = Function { id: func };
|
||||
if !self.is_bound_method {
|
||||
return None;
|
||||
}
|
||||
let func = self.as_function()?;
|
||||
Some((
|
||||
func.self_param(db)?,
|
||||
self.ty.derived(self.sig.skip_binder().inputs_and_output.inputs()[0]),
|
||||
@@ -6350,7 +6689,12 @@ fn container(&self, db: &dyn HirDatabase) -> ItemContainer {
|
||||
|
||||
impl HasContainer for Function {
|
||||
fn container(&self, db: &dyn HirDatabase) -> ItemContainer {
|
||||
container_id_to_hir(self.id.lookup(db).container)
|
||||
match self.id {
|
||||
AnyFunctionId::FunctionId(id) => container_id_to_hir(id.lookup(db).container),
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { impl_, .. } => {
|
||||
ItemContainer::Impl(Impl { id: AnyImplId::BuiltinDeriveImplId(impl_) })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6402,11 +6746,79 @@ fn container(&self, db: &dyn HirDatabase) -> ItemContainer {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait HasName {
|
||||
fn name(&self, db: &dyn HirDatabase) -> Option<Name>;
|
||||
}
|
||||
|
||||
macro_rules! impl_has_name {
|
||||
( $( $ty:ident ),* $(,)? ) => {
|
||||
$(
|
||||
impl HasName for $ty {
|
||||
fn name(&self, db: &dyn HirDatabase) -> Option<Name> {
|
||||
(*self).name(db).into()
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
impl_has_name!(
|
||||
ModuleDef,
|
||||
Module,
|
||||
Field,
|
||||
Struct,
|
||||
Union,
|
||||
Enum,
|
||||
Variant,
|
||||
Adt,
|
||||
VariantDef,
|
||||
DefWithBody,
|
||||
Function,
|
||||
ExternCrateDecl,
|
||||
Const,
|
||||
Static,
|
||||
Trait,
|
||||
TypeAlias,
|
||||
Macro,
|
||||
ExternAssocItem,
|
||||
AssocItem,
|
||||
Local,
|
||||
DeriveHelper,
|
||||
ToolModule,
|
||||
Label,
|
||||
GenericParam,
|
||||
TypeParam,
|
||||
LifetimeParam,
|
||||
ConstParam,
|
||||
TypeOrConstParam,
|
||||
InlineAsmOperand,
|
||||
);
|
||||
|
||||
macro_rules! impl_has_name_no_db {
|
||||
( $( $ty:ident ),* $(,)? ) => {
|
||||
$(
|
||||
impl HasName for $ty {
|
||||
fn name(&self, _db: &dyn HirDatabase) -> Option<Name> {
|
||||
(*self).name().into()
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
impl_has_name_no_db!(TupleField, StaticLifetime, BuiltinType, BuiltinAttr);
|
||||
|
||||
impl HasName for Param<'_> {
|
||||
fn name(&self, db: &dyn HirDatabase) -> Option<Name> {
|
||||
self.name(db)
|
||||
}
|
||||
}
|
||||
|
||||
fn container_id_to_hir(c: ItemContainerId) -> ItemContainer {
|
||||
match c {
|
||||
ItemContainerId::ExternBlockId(id) => ItemContainer::ExternBlock(ExternBlock { id }),
|
||||
ItemContainerId::ModuleId(id) => ItemContainer::Module(Module { id }),
|
||||
ItemContainerId::ImplId(id) => ItemContainer::Impl(Impl { id }),
|
||||
ItemContainerId::ImplId(id) => ItemContainer::Impl(id.into()),
|
||||
ItemContainerId::TraitId(id) => ItemContainer::Trait(Trait { id }),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
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 @@
|
||||
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 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 @@ pub(crate) fn in_type_ns(&self) -> Option<TypeNs> {
|
||||
| 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 @@ pub fn resolve_range_expr(&self, range_expr: &ast::RangeExpr) -> Option<Struct>
|
||||
}
|
||||
|
||||
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 @@ pub fn resolve_trait_impl_method(
|
||||
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 @@ pub fn resolve_trait_impl_method(
|
||||
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 @@ fn resolve_range_expr(&self, range_expr: &ast::RangeExpr) -> Option<StructId> {
|
||||
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 @@ pub fn resolve_macro_call_arm(&self, macro_call: &ast::MacroCall) -> Option<u32>
|
||||
}
|
||||
|
||||
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 @@ pub fn get_unsafe_ops_for_unsafe_block(&self, block: ast::BlockExpr) -> Vec<Expr
|
||||
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 @@ pub fn scope_at_offset(
|
||||
}
|
||||
|
||||
/// 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 @@ pub fn is_inside_unsafe(&self, expr: &ast::Expr) -> bool {
|
||||
|
||||
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 @@ pub fn is_inside_unsafe(&self, expr: &ast::Expr) -> bool {
|
||||
}
|
||||
|
||||
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 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 @@ pub(crate) fn resolve_method_call(
|
||||
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 @@ pub(crate) fn resolve_method_call_fallback(
|
||||
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 @@ pub(crate) fn resolve_field_fallback(
|
||||
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 @@ pub(crate) fn resolve_await_to_poll(
|
||||
&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 @@ pub(crate) fn resolve_prefix_expr(
|
||||
&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 @@ pub(crate) fn resolve_index_expr(
|
||||
&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 @@ pub(crate) fn resolve_bin_expr(
|
||||
&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 @@ pub(crate) fn resolve_try_expr(
|
||||
&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 @@ pub(crate) fn resolve_path(
|
||||
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 @@ pub(crate) fn resolve_path(
|
||||
.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 @@ pub(crate) fn resolve_path(
|
||||
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 @@ fn resolve_impl_method_or_trait_def(
|
||||
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 @@ fn resolve_impl_method_or_trait_def_with_subst(
|
||||
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(
|
||||
|
||||
+12
-12
@@ -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 rec(
|
||||
)
|
||||
});
|
||||
|
||||
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 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 @@ pub(crate) fn from_named(
|
||||
)
|
||||
}
|
||||
|
||||
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 @@ fn container_name(self, db: &RootDatabase) -> Option<Symbol> {
|
||||
|
||||
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 @@ fn try_to_nav(
|
||||
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 @@ fn try_to_nav(
|
||||
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 @@ fn try_to_nav(
|
||||
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 @@ impl<T> r#trait for r#struct<T> {}
|
||||
[
|
||||
"(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 @@ pub(super) fn prefill() -> DashMap<Symbol, (), BuildHasherDefault<FxHasher>> {
|
||||
arbitrary_self_types,
|
||||
arbitrary_self_types_pointers,
|
||||
supertrait_item_shadowing,
|
||||
hash,
|
||||
partial_cmp,
|
||||
cmp,
|
||||
CoerceUnsized,
|
||||
DispatchFromDyn,
|
||||
define_opaque,
|
||||
}
|
||||
|
||||
@@ -693,21 +693,24 @@ fn run_mir_lowering(&self, db: &RootDatabase, bodies: &[DefWithBody], verbosity:
|
||||
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 @@ fn run_mir_lowering(&self, db: &RootDatabase, bodies: &[DefWithBody], verbosity:
|
||||
.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 @@ fn run_inference(
|
||||
|
||||
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 @@ fn run_inference(
|
||||
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 @@ fn run_inference(
|
||||
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 @@ fn run_inference(
|
||||
}
|
||||
};
|
||||
// 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 @@ fn run_body_lowering(
|
||||
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 @@ fn run_body_lowering(
|
||||
bar.println(msg());
|
||||
}
|
||||
bar.set_message(msg);
|
||||
db.body(body_id.into());
|
||||
db.body(body_def_id);
|
||||
bar.inc(1);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user