Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-def/src/db.rs7
-rw-r--r--crates/hir-def/src/lang_item.rs40
-rw-r--r--crates/hir/src/lib.rs24
-rw-r--r--crates/ide-db/src/defs.rs24
-rw-r--r--crates/ide/src/hover/render.rs79
-rw-r--r--crates/ide/src/hover/tests.rs756
-rw-r--r--crates/test-utils/src/minicore.rs2
7 files changed, 557 insertions, 375 deletions
diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs
index 2fd2f18ee4..d25d41c2cf 100644
--- a/crates/hir-def/src/db.rs
+++ b/crates/hir-def/src/db.rs
@@ -200,7 +200,7 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
fn attrs(&self, def: AttrDefId) -> Attrs;
#[salsa::transparent]
- #[salsa::invoke(lang_item::lang_attr_query)]
+ #[salsa::invoke(lang_item::lang_attr)]
fn lang_attr(&self, def: AttrDefId) -> Option<LangItem>;
// endregion:attrs
@@ -228,6 +228,11 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
#[salsa::invoke(LangItems::crate_lang_items_query)]
fn crate_lang_items(&self, krate: CrateId) -> Option<Arc<LangItems>>;
+ #[salsa::invoke(crate::lang_item::notable_traits_in_deps)]
+ fn notable_traits_in_deps(&self, krate: CrateId) -> Arc<[Arc<[TraitId]>]>;
+ #[salsa::invoke(crate::lang_item::crate_notable_traits)]
+ fn crate_notable_traits(&self, krate: CrateId) -> Option<Arc<[TraitId]>>;
+
fn crate_supports_no_std(&self, crate_id: CrateId) -> bool;
}
diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs
index 45ba939b8c..adb2d78543 100644
--- a/crates/hir-def/src/lang_item.rs
+++ b/crates/hir-def/src/lang_item.rs
@@ -184,17 +184,53 @@ impl LangItems {
T: Into<AttrDefId> + Copy,
{
let _p = profile::span("collect_lang_item");
- if let Some(lang_item) = db.lang_attr(item.into()) {
+ if let Some(lang_item) = lang_attr(db, item.into()) {
self.items.entry(lang_item).or_insert_with(|| constructor(item));
}
}
}
-pub(crate) fn lang_attr_query(db: &dyn DefDatabase, item: AttrDefId) -> Option<LangItem> {
+pub(crate) fn lang_attr(db: &dyn DefDatabase, item: AttrDefId) -> Option<LangItem> {
let attrs = db.attrs(item);
attrs.by_key("lang").string_value().and_then(|it| LangItem::from_str(&it))
}
+pub(crate) fn notable_traits_in_deps(
+ db: &dyn DefDatabase,
+ krate: CrateId,
+) -> Arc<[Arc<[TraitId]>]> {
+ let _p = profile::span("notable_traits_in_deps").detail(|| format!("{krate:?}"));
+ let crate_graph = db.crate_graph();
+
+ Arc::from_iter(
+ crate_graph.transitive_deps(krate).filter_map(|krate| db.crate_notable_traits(krate)),
+ )
+}
+
+pub(crate) fn crate_notable_traits(db: &dyn DefDatabase, krate: CrateId) -> Option<Arc<[TraitId]>> {
+ let _p = profile::span("crate_notable_traits").detail(|| format!("{krate:?}"));
+
+ let mut traits = Vec::new();
+
+ let crate_def_map = db.crate_def_map(krate);
+
+ for (_, module_data) in crate_def_map.modules() {
+ for def in module_data.scope.declarations() {
+ if let ModuleDefId::TraitId(trait_) = def {
+ if db.attrs(trait_.into()).has_doc_notable_trait() {
+ traits.push(trait_);
+ }
+ }
+ }
+ }
+
+ if traits.is_empty() {
+ None
+ } else {
+ Some(traits.into_iter().collect())
+ }
+}
+
pub enum GenericRequirement {
None,
Minimum(usize),
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index ab42cbeecc..9866393e54 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -2844,6 +2844,7 @@ impl AssocItem {
AssocItem::TypeAlias(it) => Some(it.name(db)),
}
}
+
pub fn module(self, db: &dyn HirDatabase) -> Module {
match self {
AssocItem::Function(f) => f.module(db),
@@ -2851,6 +2852,7 @@ impl AssocItem {
AssocItem::TypeAlias(t) => t.module(db),
}
}
+
pub fn container(self, db: &dyn HirDatabase) -> AssocItemContainer {
let container = match self {
AssocItem::Function(it) => it.id.lookup(db.upcast()).container,
@@ -2886,6 +2888,27 @@ impl AssocItem {
AssocItemContainer::Impl(i) => i.trait_(db),
}
}
+
+ pub fn as_function(self) -> Option<Function> {
+ match self {
+ Self::Function(v) => Some(v),
+ _ => None,
+ }
+ }
+
+ pub fn as_const(self) -> Option<Const> {
+ match self {
+ Self::Const(v) => Some(v),
+ _ => None,
+ }
+ }
+
+ pub fn as_type_alias(self) -> Option<TypeAlias> {
+ match self {
+ Self::TypeAlias(v) => Some(v),
+ _ => None,
+ }
+ }
}
impl HasVisibility for AssocItem {
@@ -3024,6 +3047,7 @@ impl LocalSource {
impl Local {
pub fn is_param(self, db: &dyn HirDatabase) -> bool {
+ // FIXME: This parses!
let src = self.primary_source(db);
match src.source.value {
Either::Left(pat) => pat
diff --git a/crates/ide-db/src/defs.rs b/crates/ide-db/src/defs.rs
index 8f55f30a2d..5995b318e8 100644
--- a/crates/ide-db/src/defs.rs
+++ b/crates/ide-db/src/defs.rs
@@ -230,23 +230,15 @@ impl Definition {
Definition::BuiltinType(it) => it.name().display(db).to_string(),
Definition::Local(it) => {
let ty = it.ty(db);
- let ty = ty.display_truncated(db, None);
+ let ty_display = ty.display_truncated(db, None);
let is_mut = if it.is_mut(db) { "mut " } else { "" };
- let desc = match it.primary_source(db).into_ident_pat() {
- Some(ident) => {
- let name = it.name(db);
- let let_kw = if ident.syntax().parent().map_or(false, |p| {
- p.kind() == SyntaxKind::LET_STMT || p.kind() == SyntaxKind::LET_EXPR
- }) {
- "let "
- } else {
- ""
- };
- format!("{let_kw}{is_mut}{}: {ty}", name.display(db))
- }
- None => format!("{is_mut}self: {ty}"),
- };
- desc
+ if it.is_self(db) {
+ format!("{is_mut}self: {ty_display}")
+ } else {
+ let name = it.name(db);
+ let let_kw = if it.is_param(db) { "" } else { "let " };
+ format!("{let_kw}{is_mut}{}: {ty_display}", name.display(db))
+ }
}
Definition::SelfType(impl_def) => {
impl_def.self_ty(db).as_adt().and_then(|adt| Definition::Adt(adt).label(db))?
diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs
index 9d449bd18e..d3a9975b2b 100644
--- a/crates/ide/src/hover/render.rs
+++ b/crates/ide/src/hover/render.rs
@@ -1,7 +1,10 @@
//! Logic for rendering the different hover messages
+use std::{mem, ops::Not};
+
use either::Either;
use hir::{
- Adt, AsAssocItem, CaptureKind, HasSource, HirDisplay, Layout, LayoutError, Semantics, TypeInfo,
+ db::DefDatabase, Adt, AsAssocItem, AssocItem, CaptureKind, HasCrate, HasSource, HirDisplay,
+ Layout, LayoutError, Semantics, TypeInfo,
};
use ide_db::{
base_db::SourceDatabase,
@@ -390,7 +393,6 @@ pub(super) fn definition(
let mod_path = definition_mod_path(db, &def);
let label = def.label(db)?;
let docs = def.docs(db, famous_defs);
-
let value = match def {
Definition::Variant(it) => {
if !it.parent_enum(db).is_data_carrying(db) {
@@ -462,14 +464,75 @@ pub(super) fn definition(
_ => None,
};
- let label = match (value, layout_info) {
- (Some(value), Some(layout_info)) => format!("{layout_info}\n{label} = {value}"),
- (Some(value), None) => format!("{label} = {value}"),
- (None, Some(layout_info)) => format!("{layout_info}\n{label}"),
- (None, None) => label,
+ let def_ty = match def {
+ Definition::Local(it) => Some(it.ty(db)),
+ Definition::GenericParam(hir::GenericParam::ConstParam(it)) => Some(it.ty(db)),
+ Definition::GenericParam(hir::GenericParam::TypeParam(it)) => Some(it.ty(db)),
+ Definition::Field(field) => Some(field.ty(db)),
+ Definition::TupleField(it) => Some(it.ty(db)),
+ Definition::Function(it) => Some(it.ty(db)),
+ Definition::Adt(it) => Some(it.ty(db)),
+ Definition::Const(it) => Some(it.ty(db)),
+ Definition::Static(it) => Some(it.ty(db)),
+ Definition::TypeAlias(it) => Some(it.ty(db)),
+ Definition::BuiltinType(it) => Some(it.ty(db)),
+ _ => None,
};
+ let notable_traits = def_ty.and_then(|ty| {
+ let mut desc = String::new();
+ let mut needs_impl_header = true;
+ for &trait_ in db.notable_traits_in_deps(ty.krate(db).into()).iter().flat_map(|it| &**it) {
+ let trait_ = trait_.into();
+ if ty.impls_trait(db, trait_, &[]) {
+ let aliases: Vec<_> = trait_
+ .items(db)
+ .into_iter()
+ .filter_map(AssocItem::as_type_alias)
+ .map(|alias| (ty.normalize_trait_assoc_type(db, &[], alias), alias.name(db)))
+ .collect();
+ desc.push_str(if mem::take(&mut needs_impl_header) {
+ " // notable traits impls: "
+ } else {
+ ", "
+ });
+ format_to!(desc, "{}", trait_.name(db).display(db),);
+ if !aliases.is_empty() {
+ desc.push('<');
+ format_to!(
+ desc,
+ "{}",
+ aliases.into_iter().format_with(", ", |(ty, name), f| {
+ f(&name.display(db))?;
+ f(&" = ")?;
+ match ty {
+ Some(ty) => f(&ty.display(db)),
+ None => f(&"?"),
+ }
+ })
+ );
+ desc.push('>');
+ }
+ }
+ }
+ desc.is_empty().not().then(|| desc)
+ });
+
+ let mut desc = String::new();
+ if let Some(notable_traits) = notable_traits {
+ desc.push_str(&notable_traits);
+ desc.push('\n');
+ }
+ if let Some(layout_info) = layout_info {
+ desc.push_str(&layout_info);
+ desc.push('\n');
+ }
+ desc.push_str(&label);
+ if let Some(value) = value {
+ desc.push_str(" = ");
+ desc.push_str(&value);
+ }
- markup(docs.map(Into::into), label, mod_path)
+ markup(docs.map(Into::into), desc, mod_path)
}
fn type_info(
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index 587a6b66c4..f8693cd1ea 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -451,16 +451,16 @@ pub fn foo() -> u32 { 1 }
fn main() { let foo_test = fo$0o(); }
"#,
expect![[r#"
- *foo*
+ *foo*
- ```rust
- test
- ```
+ ```rust
+ test
+ ```
- ```rust
- pub fn foo() -> u32
- ```
- "#]],
+ ```rust
+ pub fn foo() -> u32
+ ```
+ "#]],
);
// Use literal `crate` in path
@@ -495,16 +495,16 @@ mod m { pub fn foo() -> super::X { super::X } }
fn main() { m::f$0oo(); }
"#,
expect![[r#"
- *foo*
+ *foo*
- ```rust
- test::m
- ```
+ ```rust
+ test::m
+ ```
- ```rust
- pub fn foo() -> super::X
- ```
- "#]],
+ ```rust
+ pub fn foo() -> super::X
+ ```
+ "#]],
);
}
@@ -559,18 +559,18 @@ pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str { }
fn main() { let foo_test = fo$0o(); }
"#,
expect![[r#"
- *foo*
+ *foo*
- ```rust
- test
- ```
+ ```rust
+ test
+ ```
- ```rust
- pub fn foo<'a, T>(b: &'a T) -> &'a str
- where
- T: AsRef<str>,
- ```
- "#]],
+ ```rust
+ pub fn foo<'a, T>(b: &'a T) -> &'a str
+ where
+ T: AsRef<str>,
+ ```
+ "#]],
);
}
@@ -583,16 +583,16 @@ pub fn foo$0(a: u32, b: u32) -> u32 {}
fn main() { }
"#,
expect![[r#"
- *foo*
+ *foo*
- ```rust
- test
- ```
+ ```rust
+ test
+ ```
- ```rust
- pub fn foo(a: u32, b: u32) -> u32
- ```
- "#]],
+ ```rust
+ pub fn foo(a: u32, b: u32) -> u32
+ ```
+ "#]],
);
}
@@ -610,27 +610,27 @@ pub fn foo$0(_: &Path) {}
fn main() { }
"#,
- expect![[r##"
- *foo*
+ expect![[r#"
+ *foo*
- ```rust
- test
- ```
+ ```rust
+ test
+ ```
- ```rust
- pub fn foo(_: &Path)
- ```
+ ```rust
+ pub fn foo(_: &Path)
+ ```
- ---
+ ---
- # Example
+ # Example
- ```
- # use std::path::Path;
- #
- foo(Path::new("hello, world!"))
- ```
- "##]],
+ ```
+ # use std::path::Path;
+ #
+ foo(Path::new("hello, world!"))
+ ```
+ "#]],
);
}
@@ -643,21 +643,21 @@ pub fn foo$0(_: &Path) {}
fn main() { }
"##,
- expect![[r##"
- *foo*
+ expect![[r#"
+ *foo*
- ```rust
- test
- ```
+ ```rust
+ test
+ ```
- ```rust
- pub fn foo(_: &Path)
- ```
+ ```rust
+ pub fn foo(_: &Path)
+ ```
- ---
+ ---
- Raw string doc attr
- "##]],
+ Raw string doc attr
+ "#]],
);
}
@@ -1040,12 +1040,12 @@ fn hover_for_param_with_multiple_traits() {
}
fn f(_x$0: impl Deref<Target=u8> + DerefMut<Target=u8>) {}"#,
expect![[r#"
- *_x*
+ *_x*
- ```rust
- _x: impl Deref<Target = u8> + DerefMut<Target = u8>
- ```
- "#]],
+ ```rust
+ _x: impl Deref<Target = u8> + DerefMut<Target = u8>
+ ```
+ "#]],
)
}
@@ -1087,15 +1087,15 @@ mod wrapper {
fn main() { let foo_test = wrapper::Thing::new$0(); }
"#,
expect![[r#"
- *new*
+ *new*
- ```rust
- test::wrapper::Thing
- ```
+ ```rust
+ test::wrapper::Thing
+ ```
- ```rust
- pub fn new() -> Thing
- ```
+ ```rust
+ pub fn new() -> Thing
+ ```
"#]],
)
}
@@ -1299,12 +1299,12 @@ fn test_hover_tuple_field() {
check(
r#"struct TS(String, i32$0);"#,
expect![[r#"
- *i32*
+ *i32*
- ```rust
- i32
- ```
- "#]],
+ ```rust
+ i32
+ ```
+ "#]],
)
}
@@ -1319,16 +1319,16 @@ id! {
}
"#,
expect![[r#"
- *foo*
+ *foo*
- ```rust
- test
- ```
+ ```rust
+ test
+ ```
- ```rust
- fn foo()
- ```
- "#]],
+ ```rust
+ fn foo()
+ ```
+ "#]],
);
}
@@ -1341,16 +1341,16 @@ fn test_hover_through_attr() {
fn foo$0() {}
"#,
expect![[r#"
- *foo*
+ *foo*
- ```rust
- test
- ```
+ ```rust
+ test
+ ```
- ```rust
- fn foo()
- ```
- "#]],
+ ```rust
+ fn foo()
+ ```
+ "#]],
);
}
@@ -1427,16 +1427,16 @@ fn foo() {
}
"#,
expect![[r#"
- *bar*
+ *bar*
- ```rust
- test
- ```
+ ```rust
+ test
+ ```
- ```rust
- fn bar() -> bool
- ```
- "#]],
+ ```rust
+ fn bar() -> bool
+ ```
+ "#]],
);
}
@@ -1483,20 +1483,20 @@ fn foo() { }
fn bar() { fo$0o(); }
",
expect![[r#"
- *foo*
+ *foo*
- ```rust
- test
- ```
+ ```rust
+ test
+ ```
- ```rust
- fn foo()
- ```
+ ```rust
+ fn foo()
+ ```
- ---
+ ---
- \<- ` ` here
- "#]],
+ \<- ` ` here
+ "#]],
);
}
@@ -1505,45 +1505,45 @@ fn test_hover_function_show_qualifiers() {
check(
r#"async fn foo$0() {}"#,
expect![[r#"
- *foo*
+ *foo*
- ```rust
- test
- ```
+ ```rust
+ test
+ ```
- ```rust
- async fn foo()
- ```
- "#]],
+ ```rust
+ async fn foo()
+ ```
+ "#]],
);
check(
r#"pub const unsafe fn foo$0() {}"#,
expect![[r#"
- *foo*
+ *foo*
- ```rust
- test
- ```
+ ```rust
+ test
+ ```
- ```rust
- pub const unsafe fn foo()
- ```
- "#]],
+ ```rust
+ pub const unsafe fn foo()
+ ```
+ "#]],
);
// Top level `pub(crate)` will be displayed as no visibility.
check(
r#"mod m { pub(crate) async unsafe extern "C" fn foo$0() {} }"#,
expect![[r#"
- *foo*
+ *foo*
- ```rust
- test::m
- ```
+ ```rust
+ test::m
+ ```
- ```rust
- pub(crate) async unsafe extern "C" fn foo()
- ```
- "#]],
+ ```rust
+ pub(crate) async unsafe extern "C" fn foo()
+ ```
+ "#]],
);
}
@@ -1552,16 +1552,16 @@ fn test_hover_function_show_types() {
check(
r#"fn foo$0(a: i32, b:i32) -> i32 { 0 }"#,
expect![[r#"
- *foo*
+ *foo*
- ```rust
- test
- ```
+ ```rust
+ test
+ ```
- ```rust
- fn foo(a: i32, b: i32) -> i32
- ```
- "#]],
+ ```rust
+ fn foo(a: i32, b: i32) -> i32
+ ```
+ "#]],
);
}
@@ -1949,39 +1949,39 @@ fn test_hover_no_links() {
pub fn fo$0o() {}
"#,
expect![[r#"
- *foo*
+ *foo*
- ```rust
- test
- ```
+ ```rust
+ test
+ ```
- ```rust
- pub fn foo()
- ```
+ ```rust
+ pub fn foo()
+ ```
- ---
+ ---
- Test cases:
- case 1. bare URL: https://www.example.com/
- case 2. inline URL with title: [example](https://www.example.com/)
- case 3. code reference: `Result`
- case 4. code reference but miss footnote: `String`
- case 5. autolink: http://www.example.com/
- case 6. email address: [email protected]
- case 7. reference: example
- case 8. collapsed link: example
- case 9. shortcut link: example
- case 10. inline without URL: example
- case 11. reference: foo
- case 12. reference: foo
- case 13. collapsed link: foo
- case 14. shortcut link: foo
- case 15. inline without URL: foo
- case 16. just escaped text: \[foo\]
- case 17. inline link: Foo
-
- [^example]: https://www.example.com/
- "#]],
+ Test cases:
+ case 1. bare URL: https://www.example.com/
+ case 2. inline URL with title: [example](https://www.example.com/)
+ case 3. code reference: `Result`
+ case 4. code reference but miss footnote: `String`
+ case 5. autolink: http://www.example.com/
+ case 6. email address: [email protected]
+ case 7. reference: example
+ case 8. collapsed link: example
+ case 9. shortcut link: example
+ case 10. inline without URL: example
+ case 11. reference: foo
+ case 12. reference: foo
+ case 13. collapsed link: foo
+ case 14. shortcut link: foo
+ case 15. inline without URL: foo
+ case 16. just escaped text: \[foo\]
+ case 17. inline link: Foo
+
+ [^example]: https://www.example.com/
+ "#]],
);
}
@@ -2091,20 +2091,20 @@ bar!();
fn foo() { let bar = Bar; bar.fo$0o(); }
"#,
expect![[r#"
- *foo*
+ *foo*
- ```rust
- test::Bar
- ```
+ ```rust
+ test::Bar
+ ```
- ```rust
- fn foo(&self)
- ```
+ ```rust
+ fn foo(&self)
+ ```
- ---
+ ---
- Do the foo
- "#]],
+ Do the foo
+ "#]],
);
}
@@ -2129,20 +2129,20 @@ bar!();
fn foo() { let bar = Bar; bar.fo$0o(); }
"#,
expect![[r#"
- *foo*
+ *foo*
- ```rust
- test::Bar
- ```
+ ```rust
+ test::Bar
+ ```
- ```rust
- fn foo(&self)
- ```
+ ```rust
+ fn foo(&self)
+ ```
- ---
+ ---
- Do the foo
- "#]],
+ Do the foo
+ "#]],
);
}
@@ -3305,7 +3305,7 @@ fn main() { let foo_test = name_with_dashes::wrapper::Thing::new$0(); }
```rust
pub fn new() -> Thing
```
- "#]],
+ "#]],
)
}
@@ -3327,7 +3327,7 @@ fn main() {
```rust
// size = 8, align = 8, niches = 1
- f: &i32
+ let f: &i32
```
---
@@ -3628,24 +3628,24 @@ fn hover_doc_block_style_indent_end() {
fn foo$0() {}
"#,
expect![[r#"
- *foo*
+ *foo*
- ```rust
- test
- ```
+ ```rust
+ test
+ ```
- ```rust
- fn foo()
- ```
+ ```rust
+ fn foo()
+ ```
- ---
+ ---
- foo
+ foo
- ```rust
- let x = 3;
- ```
- "#]],
+ ```rust
+ let x = 3;
+ ```
+ "#]],
);
}
@@ -3704,12 +3704,12 @@ trait TraitB {}
impl<T: TraitA + TraitB> Foo<T$0> where T: Sized {}
"#,
expect![[r#"
- *T*
+ *T*
- ```rust
- T: TraitA + TraitB
- ```
- "#]],
+ ```rust
+ T: TraitA + TraitB
+ ```
+ "#]],
);
check(
r#"
@@ -3718,12 +3718,12 @@ struct Foo<T>(T);
impl<T> Foo<T$0> {}
"#,
expect![[r#"
- *T*
+ *T*
- ```rust
- T
- ```
- "#]],
+ ```rust
+ T
+ ```
+ "#]],
);
// lifetimes bounds arent being tracked yet
check(
@@ -3733,12 +3733,12 @@ struct Foo<T>(T);
impl<T: 'static> Foo<T$0> {}
"#,
expect![[r#"
- *T*
+ *T*
- ```rust
- T
- ```
- "#]],
+ ```rust
+ T
+ ```
+ "#]],
);
}
@@ -3753,12 +3753,12 @@ struct Foo<T>(T);
impl<T: Trait> Foo<T$0> {}
"#,
expect![[r#"
- *T*
+ *T*
- ```rust
- T: Trait
- ```
- "#]],
+ ```rust
+ T: Trait
+ ```
+ "#]],
);
check(
r#"
@@ -3768,12 +3768,12 @@ struct Foo<T>(T);
impl<T: Trait + ?Sized> Foo<T$0> {}
"#,
expect![[r#"
- *T*
+ *T*
- ```rust
- T: Trait + ?Sized
- ```
- "#]],
+ ```rust
+ T: Trait + ?Sized
+ ```
+ "#]],
);
}
@@ -3788,12 +3788,12 @@ mod type_param_sized_bounds {
fn foo<T$0>() {}
"#,
expect![[r#"
- *T*
+ *T*
- ```rust
- T
- ```
- "#]],
+ ```rust
+ T
+ ```
+ "#]],
);
}
@@ -3805,12 +3805,12 @@ fn foo<T$0>() {}
fn foo<T$0: Sized>() {}
"#,
expect![[r#"
- *T*
+ *T*
- ```rust
- T
- ```
- "#]],
+ ```rust
+ T
+ ```
+ "#]],
);
}
@@ -3822,12 +3822,12 @@ fn foo<T$0: Sized>() {}
fn foo<T$0: ?Sized>() {}
"#,
expect![[r#"
- *T*
+ *T*
- ```rust
- T: ?Sized
- ```
- "#]],
+ ```rust
+ T: ?Sized
+ ```
+ "#]],
);
}
@@ -3840,12 +3840,12 @@ trait Trait {}
fn foo<T$0: Trait>() {}
"#,
expect![[r#"
- *T*
+ *T*
- ```rust
- T: Trait
- ```
- "#]],
+ ```rust
+ T: Trait
+ ```
+ "#]],
);
}
@@ -3858,12 +3858,12 @@ trait Trait {}
fn foo<T$0: Trait + Sized>() {}
"#,
expect![[r#"
- *T*
+ *T*
- ```rust
- T: Trait
- ```
- "#]],
+ ```rust
+ T: Trait
+ ```
+ "#]],
);
}
@@ -3876,12 +3876,12 @@ trait Trait {}
fn foo<T$0: Trait + ?Sized>() {}
"#,
expect![[r#"
- *T*
+ *T*
- ```rust
- T: Trait + ?Sized
- ```
- "#]],
+ ```rust
+ T: Trait + ?Sized
+ ```
+ "#]],
);
}
@@ -3893,12 +3893,12 @@ fn foo<T$0: Trait + ?Sized>() {}
fn foo<T$0: ?Sized + Sized + Sized>() {}
"#,
expect![[r#"
- *T*
+ *T*
- ```rust
- T
- ```
- "#]],
+ ```rust
+ T
+ ```
+ "#]],
);
check(
r#"
@@ -3907,12 +3907,12 @@ trait Trait {}
fn foo<T$0: Sized + ?Sized + Sized + Trait>() {}
"#,
expect![[r#"
- *T*
+ *T*
- ```rust
- T: Trait
- ```
- "#]],
+ ```rust
+ T: Trait
+ ```
+ "#]],
);
}
}
@@ -3947,12 +3947,12 @@ struct Foo<const LEN: usize>;
impl<const LEN: usize> Foo<LEN$0> {}
"#,
expect![[r#"
- *LEN*
+ *LEN*
- ```rust
- const LEN: usize
- ```
- "#]],
+ ```rust
+ const LEN: usize
+ ```
+ "#]],
);
}
@@ -4082,20 +4082,20 @@ fn main() {
}
"#,
expect![[r#"
- *B*
+ *B*
- ```rust
- test
- ```
+ ```rust
+ test
+ ```
- ```rust
- const B: bool = true
- ```
+ ```rust
+ const B: bool = true
+ ```
- ---
+ ---
- true
- "#]],
+ true
+ "#]],
);
check(
@@ -4119,16 +4119,16 @@ fn main() {
}
"#,
expect![[r#"
- *AA*
+ *AA*
- ```rust
- test
- ```
+ ```rust
+ test
+ ```
- ```rust
- const AA: A = A { i: 5 }
- ```
- "#]],
+ ```rust
+ const AA: A = A { i: 5 }
+ ```
+ "#]],
);
check(
@@ -5045,17 +5045,17 @@ const _: &str$0 = ""; }
mod prim_str {}
"#,
expect![[r#"
- *str*
+ *str*
- ```rust
- str
- ```
+ ```rust
+ str
+ ```
- ---
+ ---
- Docs for prim_str
- [`foo`](https://doc.rust-lang.org/nightly/std/keyword.foo.html)
- "#]],
+ Docs for prim_str
+ [`foo`](https://doc.rust-lang.org/nightly/std/keyword.foo.html)
+ "#]],
);
}
@@ -5081,20 +5081,20 @@ fn main() {
}
"#,
expect![[r#"
- *bar*
+ *bar*
- ```rust
- test
- ```
+ ```rust
+ test
+ ```
- ```rust
- fn bar<'t, T>(s: &mut S<'t, T>, t: u32) -> *mut u32
- where
- T: Clone + 't,
- 't: 't + 't,
- for<'a> T: Clone + 'a,
- ```
- "#]],
+ ```rust
+ fn bar<'t, T>(s: &mut S<'t, T>, t: u32) -> *mut u32
+ where
+ T: Clone + 't,
+ 't: 't + 't,
+ for<'a> T: Clone + 'a,
+ ```
+ "#]],
)
}
@@ -5164,16 +5164,16 @@ impl T1 for Foo {
}
"#,
expect![[r#"
-*Bar*
+ *Bar*
-```rust
-test::t2
-```
+ ```rust
+ test::t2
+ ```
-```rust
-pub type Bar
-```
-"#]],
+ ```rust
+ pub type Bar
+ ```
+ "#]],
);
}
#[test]
@@ -5186,16 +5186,16 @@ trait A {
type Assoc;
}"#,
expect![[r#"
- *Assoc*
+ *Assoc*
- ```rust
- test
- ```
+ ```rust
+ test
+ ```
- ```rust
- type Assoc
- ```
- "#]],
+ ```rust
+ type Assoc
+ ```
+ "#]],
);
check(
r#"
@@ -5207,16 +5207,16 @@ trait A {
type Assoc;
}"#,
expect![[r#"
- *Assoc*
+ *Assoc*
- ```rust
- test
- ```
+ ```rust
+ test
+ ```
- ```rust
- type Assoc
- ```
- "#]],
+ ```rust
+ type Assoc
+ ```
+ "#]],
);
check(
r#"
@@ -5226,16 +5226,16 @@ trait A where
type Assoc;
}"#,
expect![[r#"
- *Assoc*
+ *Assoc*
- ```rust
- test
- ```
+ ```rust
+ test
+ ```
- ```rust
- type Assoc
- ```
- "#]],
+ ```rust
+ type Assoc
+ ```
+ "#]],
);
}
@@ -7059,3 +7059,63 @@ fn main() {
"#]],
);
}
+
+#[test]
+fn notable_local() {
+ check(
+ r#"
+#[doc(notable_trait)]
+trait Notable {
+ type Assoc;
+ type Assoc2;
+}
+
+impl Notable for u32 {
+ type Assoc = &str;
+ type Assoc2 = char;
+}
+fn main(notable$0: u32) {}
+"#,
+ expect![[r#"
+ *notable*
+
+ ```rust
+ // notable traits impls: Notable<Assoc = &str, Assoc2 = char>
+ // size = 4, align = 4
+ notable: u32
+ ```
+ "#]],
+ );
+}
+
+#[test]
+fn notable_foreign() {
+ check(
+ r#"
+//- minicore: future, iterator
+struct S;
+#[doc(notable_trait)]
+trait Notable {}
+impl Notable for S$0 {}
+impl core::future::Future for S {
+ type Output = u32;
+}
+impl Iterator for S {
+ type Item = S;
+}
+"#,
+ expect![[r#"
+ *S*
+
+ ```rust
+ test
+ ```
+
+ ```rust
+ // notable traits impls: Notable, Future<Output = u32>, Iterator<Item = S>
+ // size = 0, align = 1
+ struct S
+ ```
+ "#]],
+ );
+}
diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs
index 3b836dfcd9..b015dd69b5 100644
--- a/crates/test-utils/src/minicore.rs
+++ b/crates/test-utils/src/minicore.rs
@@ -1166,6 +1166,7 @@ pub mod future {
task::{Context, Poll},
};
+ #[doc(notable_trait)]
#[lang = "future_trait"]
pub trait Future {
type Output;
@@ -1264,6 +1265,7 @@ pub mod iter {
mod traits {
mod iterator {
+ #[doc(notable_trait)]
pub trait Iterator {
type Item;
#[lang = "next"]