Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-def/src/expr_store/pretty.rs5
-rw-r--r--crates/hir-def/src/lang_item.rs19
-rw-r--r--crates/hir-def/src/resolver.rs9
-rw-r--r--crates/hir/src/lib.rs8
-rw-r--r--crates/ide-assists/src/handlers/add_missing_impl_members.rs63
-rw-r--r--crates/ide-db/src/traits.rs47
-rw-r--r--crates/intern/src/symbol/symbols.rs1
-rw-r--r--crates/test-utils/src/minicore.rs4
8 files changed, 136 insertions, 20 deletions
diff --git a/crates/hir-def/src/expr_store/pretty.rs b/crates/hir-def/src/expr_store/pretty.rs
index 293adfc9bd..ccc08a34d7 100644
--- a/crates/hir-def/src/expr_store/pretty.rs
+++ b/crates/hir-def/src/expr_store/pretty.rs
@@ -14,7 +14,7 @@ use stdx::never;
use syntax::ast::{HasName, RangeOp};
use crate::{
- AdtId, DefWithBodyId, FunctionId, GenericDefId, StructId, TypeParamId, VariantId,
+ AdtId, DefWithBodyId, FunctionId, GenericDefId, MacroId, StructId, TypeParamId, VariantId,
attrs::AttrFlags,
expr_store::path::{GenericArg, GenericArgs},
hir::{
@@ -1136,6 +1136,9 @@ impl Printer<'_> {
LangItemTarget::TraitId(it) => write_name!(it),
LangItemTarget::EnumVariantId(it) => write_name!(it),
LangItemTarget::ConstId(it) => write_name!(it),
+ LangItemTarget::MacroId(MacroId::Macro2Id(it)) => write_name!(it),
+ LangItemTarget::MacroId(MacroId::MacroRulesId(it)) => write_name!(it),
+ LangItemTarget::MacroId(MacroId::ProcMacroId(it)) => write_name!(it),
}
if let Some(s) = s {
diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs
index f9d5a843bd..04dfdb7d16 100644
--- a/crates/hir-def/src/lang_item.rs
+++ b/crates/hir-def/src/lang_item.rs
@@ -26,10 +26,11 @@ pub enum LangItemTarget {
TraitId(TraitId),
EnumVariantId(EnumVariantId),
ConstId(ConstId),
+ MacroId(MacroId),
}
impl_from!(
- EnumId, FunctionId, ImplId, StaticId, StructId, UnionId, TypeAliasId, TraitId, EnumVariantId, ConstId for LangItemTarget
+ EnumId, FunctionId, ImplId, StaticId, StructId, UnionId, TypeAliasId, TraitId, EnumVariantId, ConstId, MacroId for LangItemTarget
);
/// Salsa query. This will look for lang items in a specific crate.
@@ -276,7 +277,6 @@ impl LangItems {
(self.BitXorAssign, &mut self.BitXorAssign_bitxor_assign, sym::bitxor_assign),
(self.BitOrAssign, &mut self.BitOrAssign_bitor_assign, sym::bitor_assign),
(self.BitAndAssign, &mut self.BitAndAssign_bitand_assign, sym::bitand_assign),
- (self.Drop, &mut self.Drop_drop, sym::drop),
(self.Debug, &mut self.Debug_fmt, sym::fmt),
(self.Deref, &mut self.Deref_deref, sym::deref),
(self.DerefMut, &mut self.DerefMut_deref_mut, sym::deref_mut),
@@ -307,6 +307,13 @@ impl LangItems {
);
Some(())
})();
+ (|| {
+ methods(
+ self.Drop?,
+ &mut [(&mut self.Drop_drop, sym::drop), (&mut self.Drop_pin_drop, sym::pin_drop)],
+ );
+ Some(())
+ })();
}
}
@@ -397,11 +404,15 @@ macro_rules! language_item_table {
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+ #[allow(non_camel_case_types)]
pub enum LangItemEnum {
$(
$(#[$attr])*
$lang_item,
)*
+ $( $non_lang_trait, )*
+ $( $non_lang_macro_field, )*
+ $( $resolve_manually, )*
}
impl LangItemEnum {
@@ -409,6 +420,9 @@ macro_rules! language_item_table {
pub fn from_lang_items(self, lang_items: &LangItems) -> Option<LangItemTarget> {
match self {
$( LangItemEnum::$lang_item => lang_items.$lang_item.map(Into::into), )*
+ $( LangItemEnum::$non_lang_trait => lang_items.$non_lang_trait.map(Into::into), )*
+ $( LangItemEnum::$non_lang_macro_field => lang_items.$non_lang_macro_field.map(Into::into), )*
+ $( LangItemEnum::$resolve_manually => lang_items.$resolve_manually.map(Into::into), )*
}
}
@@ -716,6 +730,7 @@ language_item_table! { LangItems =>
PartialOrd_ge, FunctionId;
PartialOrd_gt, FunctionId;
Drop_drop, FunctionId;
+ Drop_pin_drop, FunctionId;
Debug_fmt, FunctionId;
Deref_deref, FunctionId;
DerefMut_deref_mut, FunctionId;
diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs
index 0062e6c170..c16ad9b4f2 100644
--- a/crates/hir-def/src/resolver.rs
+++ b/crates/hir-def/src/resolver.rs
@@ -195,7 +195,8 @@ impl<'db> Resolver<'db> {
LangItemTarget::FunctionId(_)
| LangItemTarget::ImplId(_)
| LangItemTarget::StaticId(_)
- | LangItemTarget::ConstId(_) => return None,
+ | LangItemTarget::ConstId(_)
+ | LangItemTarget::MacroId(_) => return None,
};
return Some((
type_ns,
@@ -343,7 +344,8 @@ impl<'db> Resolver<'db> {
| LangItemTarget::ImplId(_)
| LangItemTarget::TypeAliasId(_)
| LangItemTarget::TraitId(_)
- | LangItemTarget::EnumId(_) => return None,
+ | LangItemTarget::EnumId(_)
+ | LangItemTarget::MacroId(_) => return None,
}),
ResolvePathResultPrefixInfo::default(),
));
@@ -359,7 +361,8 @@ impl<'db> Resolver<'db> {
LangItemTarget::FunctionId(_)
| LangItemTarget::ImplId(_)
| LangItemTarget::StaticId(_)
- | LangItemTarget::ConstId(_) => return None,
+ | LangItemTarget::ConstId(_)
+ | LangItemTarget::MacroId(_) => return None,
};
// Remaining segments start from 0 because lang paths have no segments other than the remaining.
return Some((
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index d187763151..3b0fbc3e40 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -2283,6 +2283,14 @@ impl fmt::Debug for Function {
}
impl Function {
+ pub fn lang(db: &dyn HirDatabase, krate: Crate, lang_item: LangItem) -> Option<Function> {
+ let lang_items = hir_def::lang_item::lang_items(db, krate.id);
+ match lang_item.from_lang_items(lang_items)? {
+ LangItemTarget::FunctionId(it) => Some(it.into()),
+ _ => None,
+ }
+ }
+
pub fn module(self, db: &dyn HirDatabase) -> Module {
match self.id {
AnyFunctionId::FunctionId(id) => id.module(db).into(),
diff --git a/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/crates/ide-assists/src/handlers/add_missing_impl_members.rs
index efbe3817e1..1e8fb51a3e 100644
--- a/crates/ide-assists/src/handlers/add_missing_impl_members.rs
+++ b/crates/ide-assists/src/handlers/add_missing_impl_members.rs
@@ -2641,4 +2641,67 @@ impl Trait for Struct {
"#,
);
}
+
+ #[test]
+ fn drop_pin_drop() {
+ check_assist_not_applicable(
+ add_missing_impl_members,
+ r#"
+//- minicore: drop, pin
+struct Foo;
+impl Drop for Foo {$0
+ fn drop(&mut self) {}
+}
+ "#,
+ );
+ check_assist_not_applicable(
+ add_missing_impl_members,
+ r#"
+//- minicore: drop, pin
+struct Foo;
+impl Drop for Foo {$0
+ fn pin_drop(self: core::pin::Pin<&mut Self>) {}
+}
+ "#,
+ );
+
+ check_assist_not_applicable(
+ add_missing_default_members,
+ r#"
+//- minicore: drop, pin
+struct Foo;
+impl Drop for Foo {$0
+ fn drop(&mut self) {}
+}
+ "#,
+ );
+ check_assist_not_applicable(
+ add_missing_default_members,
+ r#"
+//- minicore: drop, pin
+struct Foo;
+impl Drop for Foo {$0
+ fn pin_drop(self: core::pin::Pin<&mut Self>) {}
+}
+ "#,
+ );
+
+ check_assist(
+ add_missing_impl_members,
+ r#"
+//- minicore: drop, pin
+struct Foo;
+impl Drop for Foo {$0
+}
+ "#,
+ r#"
+struct Foo;
+impl Drop for Foo {
+ fn drop(&mut self) {
+ ${0:todo!()}
+ }
+}
+ "#,
+ );
+ }
}
diff --git a/crates/ide-db/src/traits.rs b/crates/ide-db/src/traits.rs
index d38d9b6708..994427ac76 100644
--- a/crates/ide-db/src/traits.rs
+++ b/crates/ide-db/src/traits.rs
@@ -1,7 +1,7 @@
//! Functionality for obtaining data related to traits from the DB.
use crate::{RootDatabase, defs::Definition};
-use hir::{AsAssocItem, Semantics, db::HirDatabase};
+use hir::{AsAssocItem, HasCrate, Semantics, db::HirDatabase, sym};
use rustc_hash::FxHashSet;
use syntax::{AstNode, ast};
@@ -51,19 +51,38 @@ pub fn get_missing_assoc_items(
}
}
- imp.trait_(sema.db).map_or(vec![], |target_trait| {
- target_trait
- .items(sema.db)
- .into_iter()
- .filter(|i| match i {
- hir::AssocItem::Function(f) => !impl_fns_consts.contains(&f.name(sema.db)),
- hir::AssocItem::TypeAlias(t) => !impl_type.contains(&t.name(sema.db)),
- hir::AssocItem::Const(c) => {
- c.name(sema.db).map(|n| !impl_fns_consts.contains(&n)).unwrap_or_default()
- }
- })
- .collect()
- })
+ let Some(target_trait) = imp.trait_(sema.db) else { return Vec::new() };
+
+ // `Drop` has two methods, `drop()` and `pin_drop()`, and you can only implement one of them, so
+ // we consider `pin_drop()` to not exist, unless you already implement it.
+ let drop_trait = hir::Trait::lang(sema.db, imp.krate(sema.db), hir::LangItem::Drop);
+ if let Some(drop_trait) = drop_trait
+ && target_trait == drop_trait
+ {
+ return if impl_fns_consts.is_empty() {
+ // No method implemented, return `drop()`.
+ let drop_drop = drop_trait.function(sema.db, sym::drop);
+ match drop_drop {
+ Some(drop_drop) => vec![hir::AssocItem::Function(drop_drop)],
+ None => Vec::new(),
+ }
+ } else {
+ // Some method is already implemented, leave it.
+ Vec::new()
+ };
+ }
+
+ target_trait
+ .items(sema.db)
+ .into_iter()
+ .filter(|i| match i {
+ hir::AssocItem::Function(f) => !impl_fns_consts.contains(&f.name(sema.db)),
+ hir::AssocItem::TypeAlias(t) => !impl_type.contains(&t.name(sema.db)),
+ hir::AssocItem::Const(c) => {
+ c.name(sema.db).map(|n| !impl_fns_consts.contains(&n)).unwrap_or_default()
+ }
+ })
+ .collect()
}
/// Converts associated trait impl items to their trait definition counterpart
diff --git a/crates/intern/src/symbol/symbols.rs b/crates/intern/src/symbol/symbols.rs
index e5f66a202e..fe303aa0e0 100644
--- a/crates/intern/src/symbol/symbols.rs
+++ b/crates/intern/src/symbol/symbols.rs
@@ -295,6 +295,7 @@ define_symbols! {
doc,
drop_in_place,
drop,
+ pin_drop,
dyn_metadata,
efiapi,
eh_catch_typeinfo,
diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs
index bd15dca609..c5ebc0d248 100644
--- a/crates/test-utils/src/minicore.rs
+++ b/crates/test-utils/src/minicore.rs
@@ -655,6 +655,10 @@ pub mod ops {
#[lang = "drop"]
pub trait Drop {
fn drop(&mut self);
+
+ // region:pin
+ fn pin_drop(self: crate::pin::Pin<&mut Self>) {}
+ // endregion:pin
}
// endregion:drop