Use FamousDefs for shorten_iterator hint
This commit is contained in:
@@ -274,24 +274,54 @@ impl TryEnum {
|
|||||||
/// somewhat similar to the known paths infra inside hir, but it different; We
|
/// somewhat similar to the known paths infra inside hir, but it different; We
|
||||||
/// want to make sure that IDE specific paths don't become interesting inside
|
/// want to make sure that IDE specific paths don't become interesting inside
|
||||||
/// the compiler itself as well.
|
/// the compiler itself as well.
|
||||||
pub(crate) struct FamousDefs<'a, 'b>(pub(crate) &'a Semantics<'b, RootDatabase>, pub(crate) Crate);
|
pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Crate);
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
impl FamousDefs<'_, '_> {
|
impl FamousDefs<'_, '_> {
|
||||||
#[cfg(test)]
|
pub const FIXTURE: &'static str = r#"//- /libcore.rs crate:core
|
||||||
pub(crate) const FIXTURE: &'static str = r#"//- /libcore.rs crate:core
|
|
||||||
pub mod convert {
|
pub mod convert {
|
||||||
pub trait From<T> {
|
pub trait From<T> {
|
||||||
fn from(T) -> Self;
|
fn from(T) -> Self;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod iter {
|
||||||
|
pub use self::traits::iterator::Iterator;
|
||||||
|
mod traits { mod iterator {
|
||||||
|
use crate::option::Option;
|
||||||
|
pub trait Iterator {
|
||||||
|
type Item;
|
||||||
|
fn next(&mut self) -> Option<Self::Item>;
|
||||||
|
}
|
||||||
|
} }
|
||||||
|
|
||||||
|
pub use self::sources::*;
|
||||||
|
mod sources {
|
||||||
|
use super::Iterator;
|
||||||
|
pub struct Repeat<A> {
|
||||||
|
element: A,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn repeat<T: Clone>(elt: T) -> Repeat<T> {
|
||||||
|
Repeat { element: elt }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Clone> Iterator for Repeat<A> {
|
||||||
|
type Item = A;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<A> {
|
||||||
|
Some(self.element.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub mod option {
|
pub mod option {
|
||||||
pub enum Option<T> { None, Some(T)}
|
pub enum Option<T> { None, Some(T)}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::{convert::From, option::Option::{self, *}};
|
pub use crate::{convert::From, iter::Iterator, option::Option::{self, *}};
|
||||||
}
|
}
|
||||||
#[prelude_import]
|
#[prelude_import]
|
||||||
pub use prelude::*;
|
pub use prelude::*;
|
||||||
@@ -305,6 +335,10 @@ pub use prelude::*;
|
|||||||
self.find_enum("core:option:Option")
|
self.find_enum("core:option:Option")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn core_iter_Iterator(&self) -> Option<Trait> {
|
||||||
|
self.find_trait("core:iter:traits:iterator:Iterator")
|
||||||
|
}
|
||||||
|
|
||||||
fn find_trait(&self, path: &str) -> Option<Trait> {
|
fn find_trait(&self, path: &str) -> Option<Trait> {
|
||||||
match self.find_def(path)? {
|
match self.find_def(path)? {
|
||||||
hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it),
|
hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it),
|
||||||
@@ -324,18 +358,21 @@ pub use prelude::*;
|
|||||||
let mut path = path.split(':');
|
let mut path = path.split(':');
|
||||||
let trait_ = path.next_back()?;
|
let trait_ = path.next_back()?;
|
||||||
let std_crate = path.next()?;
|
let std_crate = path.next()?;
|
||||||
let std_crate = self
|
let std_crate = if self
|
||||||
.1
|
.1
|
||||||
.dependencies(db)
|
.declaration_name(db)
|
||||||
.into_iter()
|
.map(|name| name.to_string() == std_crate)
|
||||||
.find(|dep| &dep.name.to_string() == std_crate)?
|
.unwrap_or(false)
|
||||||
.krate;
|
{
|
||||||
|
self.1
|
||||||
|
} else {
|
||||||
|
self.1.dependencies(db).into_iter().find(|dep| dep.name.to_string() == std_crate)?.krate
|
||||||
|
};
|
||||||
let mut module = std_crate.root_module(db);
|
let mut module = std_crate.root_module(db);
|
||||||
for segment in path {
|
for segment in path {
|
||||||
module = module.children(db).find_map(|child| {
|
module = module.children(db).find_map(|child| {
|
||||||
let name = child.name(db)?;
|
let name = child.name(db)?;
|
||||||
if &name.to_string() == segment {
|
if name.to_string() == segment {
|
||||||
Some(child)
|
Some(child)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@@ -343,7 +380,7 @@ pub use prelude::*;
|
|||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
let def =
|
let def =
|
||||||
module.scope(db, None).into_iter().find(|(name, _def)| &name.to_string() == trait_)?.1;
|
module.scope(db, None).into_iter().find(|(name, _def)| name.to_string() == trait_)?.1;
|
||||||
Some(def)
|
Some(def)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use hir::{known, Adt, AssocItem, Callable, HirDisplay, ModuleDef, Semantics, Type};
|
use assists::utils::FamousDefs;
|
||||||
|
use hir::{known, Adt, AssocItem, Callable, HirDisplay, Semantics, Type};
|
||||||
use ide_db::RootDatabase;
|
use ide_db::RootDatabase;
|
||||||
use stdx::to_lower_snake_case;
|
use stdx::to_lower_snake_case;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
@@ -194,7 +195,7 @@ fn get_bind_pat_hints(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let db = sema.db;
|
let db = sema.db;
|
||||||
if let Some(hint) = hint_iterator(db, config, &ty, pat.clone()) {
|
if let Some(hint) = hint_iterator(sema, config, &ty, pat.clone()) {
|
||||||
acc.push(hint);
|
acc.push(hint);
|
||||||
} else {
|
} else {
|
||||||
acc.push(InlayHint {
|
acc.push(InlayHint {
|
||||||
@@ -209,45 +210,44 @@ fn get_bind_pat_hints(
|
|||||||
|
|
||||||
/// Checks if the type is an Iterator from std::iter and replaces its hint with an `impl Iterator<Item = Ty>`.
|
/// Checks if the type is an Iterator from std::iter and replaces its hint with an `impl Iterator<Item = Ty>`.
|
||||||
fn hint_iterator(
|
fn hint_iterator(
|
||||||
db: &RootDatabase,
|
sema: &Semantics<RootDatabase>,
|
||||||
config: &InlayHintsConfig,
|
config: &InlayHintsConfig,
|
||||||
ty: &Type,
|
ty: &Type,
|
||||||
pat: ast::IdentPat,
|
pat: ast::IdentPat,
|
||||||
) -> Option<InlayHint> {
|
) -> Option<InlayHint> {
|
||||||
|
let db = sema.db;
|
||||||
let strukt = ty.as_adt()?;
|
let strukt = ty.as_adt()?;
|
||||||
let krate = strukt.krate(db)?;
|
let krate = strukt.krate(db)?;
|
||||||
let module = strukt.module(db);
|
|
||||||
if krate.declaration_name(db).as_deref() != Some("core") {
|
if krate.declaration_name(db).as_deref() != Some("core") {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let module = module
|
// assert this type comes from `core::iter`
|
||||||
|
strukt
|
||||||
|
.module(db)
|
||||||
.path_to_root(db)
|
.path_to_root(db)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.rev()
|
.rev()
|
||||||
.find(|module| module.name(db) == Some(known::iter))?;
|
.find(|module| module.name(db) == Some(known::iter))?;
|
||||||
let iter_trait = module.scope(db, None).into_iter().find_map(|(name, def)| match def {
|
let iter_trait = FamousDefs(sema, krate).core_iter_Iterator()?;
|
||||||
hir::ScopeDef::ModuleDef(ModuleDef::Trait(r#trait)) if name == known::Iterator => {
|
|
||||||
Some(r#trait)
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
})?;
|
|
||||||
if ty.impls_trait(db, iter_trait, &[]) {
|
if ty.impls_trait(db, iter_trait, &[]) {
|
||||||
let assoc_type_item = iter_trait.items(db).into_iter().find_map(|item| match item {
|
let assoc_type_item = iter_trait.items(db).into_iter().find_map(|item| match item {
|
||||||
AssocItem::TypeAlias(alias) if alias.name(db) == known::Item => Some(alias),
|
AssocItem::TypeAlias(alias) if alias.name(db) == known::Item => Some(alias),
|
||||||
_ => None,
|
_ => None,
|
||||||
})?;
|
})?;
|
||||||
if let Some(ty) = ty.normalize_trait_assoc_type(db, iter_trait, &[], assoc_type_item) {
|
if let Some(ty) = ty.normalize_trait_assoc_type(db, iter_trait, &[], assoc_type_item) {
|
||||||
|
const LABEL_START: &str = "impl Iterator<Item = ";
|
||||||
|
const LABEL_END: &str = ">";
|
||||||
|
|
||||||
|
let ty_display = ty.display_truncated(
|
||||||
|
db,
|
||||||
|
config
|
||||||
|
.max_length
|
||||||
|
.map(|len| len.saturating_sub(LABEL_START.len() + LABEL_END.len())),
|
||||||
|
);
|
||||||
return Some(InlayHint {
|
return Some(InlayHint {
|
||||||
range: pat.syntax().text_range(),
|
range: pat.syntax().text_range(),
|
||||||
kind: InlayKind::TypeHint,
|
kind: InlayKind::TypeHint,
|
||||||
label: format!(
|
label: format!("{}{}{}", LABEL_START, ty_display, LABEL_END).into(),
|
||||||
"impl Iterator<Item = {}>",
|
|
||||||
ty.display_truncated(
|
|
||||||
db,
|
|
||||||
config.max_length.map(|len| len - 22 /*len of the template string above*/)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -401,6 +401,7 @@ fn get_callable(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<Call
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use assists::utils::FamousDefs;
|
||||||
use expect_test::{expect, Expect};
|
use expect_test::{expect, Expect};
|
||||||
use test_utils::extract_annotations;
|
use test_utils::extract_annotations;
|
||||||
|
|
||||||
@@ -1124,15 +1125,26 @@ fn main() {
|
|||||||
chaining_hints: true,
|
chaining_hints: true,
|
||||||
max_length: None,
|
max_length: None,
|
||||||
},
|
},
|
||||||
r#"
|
&format!(
|
||||||
|
"{}\n{}\n",
|
||||||
|
r#"
|
||||||
//- /main.rs crate:main deps:std
|
//- /main.rs crate:main deps:std
|
||||||
use std::{Option::{self, Some, None}, iter};
|
use std::{Option::{self, Some, None}, iter};
|
||||||
|
|
||||||
|
struct MyIter;
|
||||||
|
|
||||||
|
impl iter::Iterator for MyIter {
|
||||||
|
type Item = ();
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
let _x = MyIter;
|
||||||
|
//^^ MyIter
|
||||||
let _x = iter::repeat(0);
|
let _x = iter::repeat(0);
|
||||||
//^^ impl Iterator<Item = i32>
|
//^^ impl Iterator<Item = i32>
|
||||||
let _y = iter::Chain(iter::repeat(0), iter::repeat(0));
|
|
||||||
//^^ impl Iterator<Item = i32>
|
|
||||||
fn generic<T: Clone>(t: T) {
|
fn generic<T: Clone>(t: T) {
|
||||||
let _x = iter::repeat(t);
|
let _x = iter::repeat(t);
|
||||||
//^^ impl Iterator<Item = T>
|
//^^ impl Iterator<Item = T>
|
||||||
@@ -1141,42 +1153,9 @@ fn main() {
|
|||||||
|
|
||||||
//- /std.rs crate:std deps:core
|
//- /std.rs crate:std deps:core
|
||||||
use core::*;
|
use core::*;
|
||||||
|
|
||||||
//- /core.rs crate:core
|
|
||||||
pub enum Option<T> {
|
|
||||||
Some(T),
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod iter {
|
|
||||||
pub use self::traits::iterator::Iterator;
|
|
||||||
pub mod traits { pub mod iterator {
|
|
||||||
pub trait Iterator {
|
|
||||||
type Item;
|
|
||||||
}
|
|
||||||
} }
|
|
||||||
|
|
||||||
pub use self::sources::*;
|
|
||||||
pub mod sources {
|
|
||||||
use super::Iterator;
|
|
||||||
pub struct Repeat<T: Clone>(pub T);
|
|
||||||
|
|
||||||
pub fn repeat<T: Clone>(t: T) -> Repeat<T> {
|
|
||||||
Repeat(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Clone> Iterator for Repeat<T> {
|
|
||||||
type Item = T;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Chain<A, B>(pub A, pub B);
|
|
||||||
|
|
||||||
impl<T, A, B> Iterator for Chain<A, B> where A: Iterator<Item = T>, B: Iterator<Item = T> {
|
|
||||||
type Item = T;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"#,
|
"#,
|
||||||
|
FamousDefs::FIXTURE
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user