diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs index 8aeb54b509ca..5900aa6cb831 100644 --- a/crates/hir-def/src/lang_item.rs +++ b/crates/hir-def/src/lang_item.rs @@ -322,6 +322,9 @@ pub fn crate_notable_traits(db: &dyn SourceDatabase, krate: Crate) -> Option Option Option> { + let mut traits = Vec::new(); + + let crate_def_map = crate_def_map(db, krate); + if !crate_def_map.features().auto_traits { + return None; + } + + for (_, module_data) in crate_def_map.modules() { + for def in module_data.scope.declarations() { + let ModuleDefId::TraitId(trait_) = def else { continue }; + let sig = crate::signatures::TraitSignature::of(db, trait_); + if sig.flags.contains(crate::signatures::TraitFlags::AUTO) { + traits.push(trait_); + } + } + } + + if traits.is_empty() { None } else { Some(traits.into_iter().collect()) } +} + macro_rules! language_item_table { ( $LangItems:ident => diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 0712a025b49c..57ea692d8271 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -92,8 +92,11 @@ use crate::{ }; pub use crate::{ - find_path::FindPathConfig, hir::type_ref, item_tree::file_item_tree, - lang_item::crate_notable_traits, signatures::LocalFieldId, + find_path::FindPathConfig, + hir::type_ref, + item_tree::file_item_tree, + lang_item::{crate_auto_traits, crate_notable_traits}, + signatures::LocalFieldId, }; pub use hir_expand::{Intern, Lookup, tt}; diff --git a/crates/hir-def/src/unstable_features.rs b/crates/hir-def/src/unstable_features.rs index 3f9f54aa8112..e985684d1735 100644 --- a/crates/hir-def/src/unstable_features.rs +++ b/crates/hir-def/src/unstable_features.rs @@ -91,4 +91,6 @@ define_unstable_features! { deref_patterns, mut_ref, type_changing_struct_update, + auto_traits, + doc_notable_trait, } diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 8f747e397c87..e97f42f69ec9 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -301,6 +301,14 @@ impl Crate { .flatten() } + pub fn auto_traits_in_deps(self, db: &dyn HirDatabase) -> impl Iterator { + self.id + .transitive_deps(db) + .into_iter() + .filter_map(|krate| hir_def::crate_auto_traits(db, krate)) + .flatten() + } + pub fn root_module(self, db: &dyn HirDatabase) -> Module { Module { id: crate_def_map(db, self.id).root_module_id() } } diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 3d73b5b0f24d..0ec985cdbc7f 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -326,6 +326,7 @@ fn hover_offset( res.extend(definitions); continue; } + res.extend(render::rpit(sema, config, &token, edition, display_target)); let keywords = || render::keyword(sema, config, &token, edition, display_target); let underscore = || { if !is_same_kind { diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index f70783fd3c0c..e746a4ef758c 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -261,6 +261,52 @@ pub(super) fn keyword( Some(HoverResult { markup, actions }) } +pub(super) fn rpit( + sema: &Semantics<'_, RootDatabase>, + _config: &HoverConfig<'_>, + token: &SyntaxToken, + edition: Edition, + display_target: DisplayTarget, +) -> Option { + // FIXME: offer on 'async' kw, outputs async fn desugared rpit + if token.kind() != T![impl] { + return None; + } + + let db = sema.db; + + let impl_type = token.parent().and_then(ast::ImplTraitType::cast)?; + // FIXME: supports nested rpit, like `Option` #23237 + let ret_type = impl_type.syntax().parent().and_then(ast::RetType::cast)?; + let func = ret_type.syntax().parent().and_then(ast::Fn::cast)?; + // XXX: Should be resolve type and iteratively the bound list, not a string + let exists = impl_type + .type_bound_list()? + .bounds() + .filter_map(|it| Some(it.ty()?.to_string())) + .collect_vec(); + + let mut res = impl_type.to_string(); + + let body = func.body()?; + let ty = sema.type_of_expr(&body.into())?.adjusted(); + + let auto_traits = sema + .scope(impl_type.syntax())? + .krate() + .auto_traits_in_deps(db) + .map(|trait_| Trait::from(*trait_)) + .filter(|trait_| trait_.is_auto(db) && ty.impls_trait(db, *trait_, &[])) + .filter(|trait_| !exists.iter().any(|it| it == trait_.name(db).as_str())); + for trait_ in auto_traits { + format_to!(res, " + {}", trait_.name(db).display(db, edition)); + } + format_to!(res, "\n{impl_type} = {}", ty.display(db, display_target)); + + let markup = format!("```rust\n{res}\n```").into(); + Some(HoverResult { markup, ..Default::default() }) +} + /// Returns missing types in a record pattern. /// Only makes sense when there's a rest pattern in the record pattern. /// i.e. `let S {a, ..} = S {a: 1, b: 2}` diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 4fea4468c072..d7f420dd19ad 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -9232,6 +9232,7 @@ fn main() { fn notable_local() { check( r#" +#![feature(doc_notable_trait)] #[doc(notable_trait)] trait Notable { type Assoc; @@ -9359,6 +9360,7 @@ fn notable_ranged() { check_hover_range( r#" //- minicore: future, iterator +#![feature(doc_notable_trait)] struct S; #[doc(notable_trait)] trait Notable {} @@ -9387,6 +9389,7 @@ fn notable_actions() { check_actions( r#" //- minicore: future, iterator +#![feature(doc_notable_trait)] struct S; struct S2; #[doc(notable_trait)] @@ -9406,7 +9409,7 @@ impl Iterator for S { file_id: FileId( 0, ), - offset: 7, + offset: 38, }, ), GoToType( @@ -9445,8 +9448,8 @@ impl Iterator for S { file_id: FileId( 0, ), - full_range: 21..59, - focus_range: 49..56, + full_range: 52..90, + focus_range: 80..87, name: "Notable", kind: Trait, description: "trait Notable", @@ -9458,8 +9461,8 @@ impl Iterator for S { file_id: FileId( 0, ), - full_range: 10..20, - focus_range: 17..19, + full_range: 41..51, + focus_range: 48..50, name: "S2", kind: Struct, description: "struct S2", @@ -10244,6 +10247,78 @@ fn f ); } +#[test] +fn rpit_keyword() { + check( + r#" +//- minicore: send, unpin +//- /main.rs crate:main deps:std +trait Trait {} +impl Trait for T {} +fn foo() -> $0impl Trait { + &raw const () +} +//- /libstd.rs crate:std +#[doc(keyword = "impl")] +/// keyword docs +mod impl_keyword {} +"#, + expect![[r#" + *impl* + ```rust + impl Trait + Unpin + impl Trait = *const () + ``` + + --- + + ```rust + impl + ``` + + --- + + keyword docs + "#]], + ); + + check( + r#" +//- minicore: send, unpin +trait Trait {} +impl Trait for T {} +fn foo() -> $0impl Trait { + 2 +} +"#, + expect![[r#" + *impl* + ```rust + impl Trait + Send + Unpin + impl Trait = i32 + ``` + "#]], + ); + + check( + r#" +//- minicore: send, unpin +trait Trait {} +impl Trait for T {} +fn foo() -> $0impl Trait + Unpin { + 2 +} +"#, + expect![[r#" + *impl* + ```rust + impl Trait + Unpin + Send + impl Trait + Unpin = i32 + ``` + "#]], + ); +} + #[test] fn issue_18613() { check( diff --git a/crates/ide/src/inlay_hints/bounds.rs b/crates/ide/src/inlay_hints/bounds.rs index 045559fd7f46..b1e3e1140c11 100644 --- a/crates/ide/src/inlay_hints/bounds.rs +++ b/crates/ide/src/inlay_hints/bounds.rs @@ -143,7 +143,7 @@ fn foo() {} file_id: FileId( 1, ), - range: 470..475, + range: 526..531, }, ), ), diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index caf123fa6809..967b9bd43a4c 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -600,7 +600,7 @@ fn main() { false, false, expect![[r#" - Some Variant FileId(1) 6735..6767 6760..6764 + Some Variant FileId(1) 6791..6823 6816..6820 FileId(0) 46..50 "#]], diff --git a/crates/intern/src/symbol/symbols.rs b/crates/intern/src/symbol/symbols.rs index 45b4c274a525..82e3c54e0184 100644 --- a/crates/intern/src/symbol/symbols.rs +++ b/crates/intern/src/symbol/symbols.rs @@ -683,6 +683,8 @@ define_symbols! { deref_patterns, mut_ref, type_changing_struct_update, + auto_traits, + doc_notable_trait, RangeMin, RangeMax, RangeSub, diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index 0d9bb4f92bdc..3da392d4c39c 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -88,6 +88,8 @@ #![rustc_coherence_is_core] #![feature(lang_items)] +#![feature(auto_traits)] +#![feature(doc_notable_trait)] pub mod marker { // region:sized