From aaa3905fdd18a7981d40ac371099ae9044e833a8 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 6 Oct 2020 19:07:34 +0200 Subject: Shorten type hints for std::iter Iterators --- crates/hir/src/code_model.rs | 37 +++++++++++- crates/hir/src/lib.rs | 2 +- crates/hir_expand/src/name.rs | 1 + crates/ide/src/inlay_hints.rs | 131 ++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 162 insertions(+), 9 deletions(-) diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index c75d46bff..031c91ccf 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs @@ -30,8 +30,12 @@ use hir_expand::{ use hir_ty::{ autoderef, display::{HirDisplayError, HirFormatter}, - method_resolution, ApplicationTy, CallableDefId, Canonical, FnSig, GenericPredicate, - InEnvironment, Substs, TraitEnvironment, Ty, TyDefId, TypeCtor, + method_resolution, + traits::Solution, + traits::SolutionVariables, + ApplicationTy, BoundVar, CallableDefId, Canonical, DebruijnIndex, FnSig, GenericPredicate, + InEnvironment, Obligation, ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, Ty, + TyDefId, TyKind, TypeCtor, }; use rustc_hash::FxHashSet; use stdx::impl_from; @@ -1362,6 +1366,35 @@ impl Type { db.trait_solve(self.krate, goal).is_some() } + pub fn normalize_trait_assoc_type( + &self, + db: &dyn HirDatabase, + r#trait: Trait, + args: &[Type], + alias: TypeAlias, + ) -> Option { + let subst = Substs::build_for_def(db, r#trait.id) + .push(self.ty.value.clone()) + .fill(args.iter().map(|t| t.ty.value.clone())) + .build(); + let predicate = ProjectionPredicate { + projection_ty: ProjectionTy { associated_ty: alias.id, parameters: subst }, + ty: Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)), + }; + let goal = Canonical { + value: InEnvironment::new( + self.ty.environment.clone(), + Obligation::Projection(predicate), + ), + kinds: Arc::new([TyKind::General]), + }; + + match db.trait_solve(self.krate, goal)? { + Solution::Unique(SolutionVariables(subst)) => subst.value.first().cloned(), + Solution::Ambig(_) => None, + } + } + pub fn is_copy(&self, db: &dyn HirDatabase) -> bool { let lang_item = db.lang_item(self.krate, SmolStr::new("copy")); let copy_trait = match lang_item { diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 171118d98..4094a76cb 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -55,7 +55,7 @@ pub use hir_def::{ type_ref::{Mutability, TypeRef}, }; pub use hir_expand::{ - name::AsName, name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, + name::known, name::AsName, name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, /* FIXME */ MacroDefId, MacroFile, Origin, }; pub use hir_ty::display::HirDisplay; diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs index a5750d829..63f828707 100644 --- a/crates/hir_expand/src/name.rs +++ b/crates/hir_expand/src/name.rs @@ -164,6 +164,7 @@ pub mod known { result, boxed, // Components of known path (type name) + Iterator, IntoIterator, Item, Try, diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 3a4dc6a84..d8e67bbd9 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -1,4 +1,4 @@ -use hir::{Adt, Callable, HirDisplay, Semantics, Type}; +use hir::{known, Adt, AssocItem, Callable, HirDisplay, ModuleDef, Semantics, Type}; use ide_db::RootDatabase; use stdx::to_lower_snake_case; use syntax::{ @@ -193,14 +193,68 @@ fn get_bind_pat_hints( return None; } - acc.push(InlayHint { - range: pat.syntax().text_range(), - kind: InlayKind::TypeHint, - label: ty.display_truncated(sema.db, config.max_length).to_string().into(), - }); + let db = sema.db; + if let Some(hint) = hint_iterator(db, config, &ty, pat.clone()) { + acc.push(hint); + } else { + acc.push(InlayHint { + range: pat.syntax().text_range(), + kind: InlayKind::TypeHint, + label: ty.display_truncated(db, config.max_length).to_string().into(), + }); + } + Some(()) } +/// Checks if the type is an Iterator from std::iter and replaces its hint with an `impl Iterator`. +fn hint_iterator( + db: &RootDatabase, + config: &InlayHintsConfig, + ty: &Type, + pat: ast::IdentPat, +) -> Option { + let strukt = ty.as_adt()?; + let krate = strukt.krate(db)?; + let module = strukt.module(db); + if krate.declaration_name(db).as_deref() != Some("core") { + return None; + } + let module = module + .path_to_root(db) + .into_iter() + .rev() + .find(|module| module.name(db) == Some(known::iter))?; + let iter_trait = module.scope(db, None).into_iter().find_map(|(name, def)| match def { + hir::ScopeDef::ModuleDef(ModuleDef::Trait(r#trait)) if name == known::Iterator => { + Some(r#trait) + } + _ => None, + })?; + if ty.impls_trait(db, iter_trait, &[]) { + 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), + _ => None, + })?; + if let Some(ty) = ty.normalize_trait_assoc_type(db, iter_trait, &[], assoc_type_item) { + return Some(InlayHint { + range: pat.syntax().text_range(), + kind: InlayKind::TypeHint, + label: format!( + "impl Iterator", + ty.display_truncated( + db, + config.max_length.map(|len| len - 22 /*len of the template string above*/) + ) + ) + .into(), + }); + } + } + + None +} + fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::IdentPat, pat_ty: &Type) -> bool { if let Some(Adt::Enum(enum_data)) = pat_ty.as_adt() { let pat_text = bind_pat.to_string(); @@ -1057,6 +1111,71 @@ fn main() { let _v = Vec::>::new(); //^^ Vec> } +"#, + ); + } + + #[test] + fn shorten_iterator_hints() { + check_with_config( + InlayHintsConfig { + parameter_hints: false, + type_hints: true, + chaining_hints: true, + max_length: None, + }, + r#" +//- /main.rs crate:main deps:std +use std::{Option::{self, Some, None}, iter}; + +fn main() { + let _x = iter::repeat(0); + //^^ impl Iterator + let _y = iter::Chain(iter::repeat(0), iter::repeat(0)); + //^^ impl Iterator + fn generic(t: T) { + let _x = iter::repeat(t); + //^^ impl Iterator + } +} + +//- /std.rs crate:std deps:core +use core::*; + +//- /core.rs crate:core +pub enum Option { + 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(pub T); + + pub fn repeat(t: T) -> Repeat { + Repeat(f) + } + + impl Iterator for Repeat { + type Item = T; + } + + pub struct Chain(pub A, pub B); + + impl Iterator for Chain where A: Iterator, B: Iterator { + type Item = T; + } + } +} "#, ); } -- cgit v1.2.3 From c6f1de6ac5d3496fc3c30b5e15263db68d057695 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 6 Oct 2020 21:05:57 +0200 Subject: Use FamousDefs for shorten_iterator hint --- crates/assists/src/utils.rs | 61 ++++++++++++++++++++++------ crates/ide/src/inlay_hints.rs | 93 +++++++++++++++++-------------------------- 2 files changed, 85 insertions(+), 69 deletions(-) diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs index eb69c49a4..0335969fd 100644 --- a/crates/assists/src/utils.rs +++ b/crates/assists/src/utils.rs @@ -274,24 +274,54 @@ impl TryEnum { /// 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 /// 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)] impl FamousDefs<'_, '_> { - #[cfg(test)] - pub(crate) const FIXTURE: &'static str = r#"//- /libcore.rs crate:core + pub const FIXTURE: &'static str = r#"//- /libcore.rs crate:core pub mod convert { pub trait From { 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; + } + } } + + pub use self::sources::*; + mod sources { + use super::Iterator; + pub struct Repeat { + element: A, + } + + pub fn repeat(elt: T) -> Repeat { + Repeat { element: elt } + } + + impl Iterator for Repeat { + type Item = A; + + fn next(&mut self) -> Option { + Some(self.element.clone()) + } + } + } +} + pub mod option { pub enum Option { None, Some(T)} } pub mod prelude { - pub use crate::{convert::From, option::Option::{self, *}}; + pub use crate::{convert::From, iter::Iterator, option::Option::{self, *}}; } #[prelude_import] pub use prelude::*; @@ -305,6 +335,10 @@ pub use prelude::*; self.find_enum("core:option:Option") } + pub fn core_iter_Iterator(&self) -> Option { + self.find_trait("core:iter:traits:iterator:Iterator") + } + fn find_trait(&self, path: &str) -> Option { match self.find_def(path)? { hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it), @@ -324,18 +358,21 @@ pub use prelude::*; let mut path = path.split(':'); let trait_ = path.next_back()?; let std_crate = path.next()?; - let std_crate = self + let std_crate = if self .1 - .dependencies(db) - .into_iter() - .find(|dep| &dep.name.to_string() == std_crate)? - .krate; - + .declaration_name(db) + .map(|name| name.to_string() == std_crate) + .unwrap_or(false) + { + 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); for segment in path { module = module.children(db).find_map(|child| { let name = child.name(db)?; - if &name.to_string() == segment { + if name.to_string() == segment { Some(child) } else { None @@ -343,7 +380,7 @@ pub use prelude::*; })?; } 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) } } diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index d8e67bbd9..27bd1e37f 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -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 stdx::to_lower_snake_case; use syntax::{ @@ -194,7 +195,7 @@ fn get_bind_pat_hints( } 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); } else { 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`. fn hint_iterator( - db: &RootDatabase, + sema: &Semantics, config: &InlayHintsConfig, ty: &Type, pat: ast::IdentPat, ) -> Option { + let db = sema.db; let strukt = ty.as_adt()?; let krate = strukt.krate(db)?; - let module = strukt.module(db); if krate.declaration_name(db).as_deref() != Some("core") { return None; } - let module = module + // assert this type comes from `core::iter` + strukt + .module(db) .path_to_root(db) .into_iter() .rev() .find(|module| module.name(db) == Some(known::iter))?; - let iter_trait = module.scope(db, None).into_iter().find_map(|(name, def)| match def { - hir::ScopeDef::ModuleDef(ModuleDef::Trait(r#trait)) if name == known::Iterator => { - Some(r#trait) - } - _ => None, - })?; + let iter_trait = FamousDefs(sema, krate).core_iter_Iterator()?; if ty.impls_trait(db, iter_trait, &[]) { 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), _ => None, })?; if let Some(ty) = ty.normalize_trait_assoc_type(db, iter_trait, &[], assoc_type_item) { + const LABEL_START: &str = "impl Iterator", - ty.display_truncated( - db, - config.max_length.map(|len| len - 22 /*len of the template string above*/) - ) - ) - .into(), + label: format!("{}{}{}", LABEL_START, ty_display, LABEL_END).into(), }); } } @@ -401,6 +401,7 @@ fn get_callable(sema: &Semantics, expr: &ast::Expr) -> Option Option { + None + } +} + fn main() { + let _x = MyIter; + //^^ MyIter let _x = iter::repeat(0); //^^ impl Iterator - let _y = iter::Chain(iter::repeat(0), iter::repeat(0)); - //^^ impl Iterator fn generic(t: T) { let _x = iter::repeat(t); //^^ impl Iterator @@ -1141,42 +1153,9 @@ fn main() { //- /std.rs crate:std deps:core use core::*; - -//- /core.rs crate:core -pub enum Option { - 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(pub T); - - pub fn repeat(t: T) -> Repeat { - Repeat(f) - } - - impl Iterator for Repeat { - type Item = T; - } - - pub struct Chain(pub A, pub B); - - impl Iterator for Chain where A: Iterator, B: Iterator { - type Item = T; - } - } -} "#, + FamousDefs::FIXTURE + ), ); } } -- cgit v1.2.3 From c133651e0a613d4833bba1c1f229222d060e2ba8 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 7 Oct 2020 10:14:42 +0200 Subject: Move IntoIterator into FamousDefs --- crates/assists/src/utils.rs | 23 +++++++++++++++-------- crates/ide/src/inlay_hints.rs | 28 +++++----------------------- 2 files changed, 20 insertions(+), 31 deletions(-) diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs index 0335969fd..b341453d4 100644 --- a/crates/assists/src/utils.rs +++ b/crates/assists/src/utils.rs @@ -286,14 +286,21 @@ pub mod convert { } 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; + pub use self::traits::{collect::IntoIterator, iterator::Iterator}; + mod traits { + mod iterator { + use crate::option::Option; + pub trait Iterator { + type Item; + fn next(&mut self) -> Option; + } + } + mod collect { + pub trait IntoIterator { + type Item; + } } - } } + } pub use self::sources::*; mod sources { @@ -321,7 +328,7 @@ pub mod option { } pub mod prelude { - pub use crate::{convert::From, iter::Iterator, option::Option::{self, *}}; + pub use crate::{convert::From, iter::{IntoIterator, Iterator}, option::Option::{self, *}}; } #[prelude_import] pub use prelude::*; diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 27bd1e37f..31a6a1be8 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -412,7 +412,8 @@ mod tests { } fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) { - let (analysis, file_id) = fixture::file(ra_fixture); + let ra_fixture = format!("{}\n{}", ra_fixture, FamousDefs::FIXTURE); + let (analysis, file_id) = fixture::file(&ra_fixture); let expected = extract_annotations(&*analysis.file_text(file_id).unwrap()); let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap(); let actual = @@ -1011,13 +1012,6 @@ fn main() { println!("Unit expr"); } -//- /core.rs crate:core -#[prelude_import] use iter::*; -mod iter { - trait IntoIterator { - type Item; - } -} //- /alloc.rs crate:alloc deps:core mod collections { struct Vec {} @@ -1059,14 +1053,6 @@ fn main() { //^ &str } } - -//- /core.rs crate:core -#[prelude_import] use iter::*; -mod iter { - trait IntoIterator { - type Item; - } -} //- /alloc.rs crate:alloc deps:core mod collections { struct Vec {} @@ -1125,15 +1111,13 @@ fn main() { chaining_hints: true, max_length: None, }, - &format!( - "{}\n{}\n", - r#" + r#" //- /main.rs crate:main deps:std -use std::{Option::{self, Some, None}, iter}; +use std::iter; struct MyIter; -impl iter::Iterator for MyIter { +impl Iterator for MyIter { type Item = (); fn next(&mut self) -> Option { None @@ -1154,8 +1138,6 @@ fn main() { //- /std.rs crate:std deps:core use core::*; "#, - FamousDefs::FIXTURE - ), ); } } -- cgit v1.2.3 From 209e9b9926d27ac71bc054bfdd48888e5d7d6d1a Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 7 Oct 2020 11:30:42 +0200 Subject: Shorten iterator chain hints --- crates/assists/src/utils.rs | 41 ++++++++++++--- crates/ide/src/inlay_hints.rs | 117 +++++++++++++++++++++++++++++------------- 2 files changed, 115 insertions(+), 43 deletions(-) diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs index b341453d4..92b3c3b00 100644 --- a/crates/assists/src/utils.rs +++ b/crates/assists/src/utils.rs @@ -281,21 +281,34 @@ impl FamousDefs<'_, '_> { pub const FIXTURE: &'static str = r#"//- /libcore.rs crate:core pub mod convert { pub trait From { - fn from(T) -> Self; + fn from(t: T) -> Self; } } pub mod iter { pub use self::traits::{collect::IntoIterator, iterator::Iterator}; mod traits { - mod iterator { + pub(crate) mod iterator { use crate::option::Option; pub trait Iterator { type Item; fn next(&mut self) -> Option; + fn by_ref(&mut self) -> &mut Self { + self + } + fn take(self, n: usize) -> crate::iter::Take { + crate::iter::Take { inner: self } + } + } + + impl Iterator for &mut I { + type Item = I::Item; + fn next(&mut self) -> Option { + (**self).next() + } } } - mod collect { + pub(crate) mod collect { pub trait IntoIterator { type Item; } @@ -303,21 +316,35 @@ pub mod iter { } pub use self::sources::*; - mod sources { + pub(crate) mod sources { use super::Iterator; + use crate::option::Option::{self, *}; pub struct Repeat { element: A, } - pub fn repeat(elt: T) -> Repeat { + pub fn repeat(elt: T) -> Repeat { Repeat { element: elt } } - impl Iterator for Repeat { + impl Iterator for Repeat { type Item = A; fn next(&mut self) -> Option { - Some(self.element.clone()) + None + } + } + } + + pub use self::adapters::*; + pub(crate) mod adapters { + use super::Iterator; + use crate::option::Option::{self, *}; + pub struct Take { pub(crate) inner: I } + impl Iterator for Take where I: Iterator { + type Item = ::Item; + fn next(&mut self) -> Option<::Item> { + None } } } diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 31a6a1be8..279d02541 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -126,11 +126,12 @@ fn get_chaining_hints( } } } - let label = ty.display_truncated(sema.db, config.max_length).to_string(); acc.push(InlayHint { range: expr.syntax().text_range(), kind: InlayKind::ChainingHint, - label: label.into(), + label: hint_iterator(sema, config, &ty).unwrap_or_else(|| { + ty.display_truncated(sema.db, config.max_length).to_string().into() + }), }); } Some(()) @@ -193,17 +194,12 @@ fn get_bind_pat_hints( if should_not_display_type_hint(sema, &pat, &ty) { return None; } - - let db = sema.db; - if let Some(hint) = hint_iterator(sema, config, &ty, pat.clone()) { - acc.push(hint); - } else { - acc.push(InlayHint { - range: pat.syntax().text_range(), - kind: InlayKind::TypeHint, - label: ty.display_truncated(db, config.max_length).to_string().into(), - }); - } + acc.push(InlayHint { + range: pat.syntax().text_range(), + kind: InlayKind::TypeHint, + label: hint_iterator(sema, config, &ty) + .unwrap_or_else(|| ty.display_truncated(sema.db, config.max_length).to_string().into()), + }); Some(()) } @@ -213,8 +209,7 @@ fn hint_iterator( sema: &Semantics, config: &InlayHintsConfig, ty: &Type, - pat: ast::IdentPat, -) -> Option { +) -> Option { let db = sema.db; let strukt = ty.as_adt()?; let krate = strukt.krate(db)?; @@ -244,11 +239,7 @@ fn hint_iterator( .max_length .map(|len| len.saturating_sub(LABEL_START.len() + LABEL_END.len())), ); - return Some(InlayHint { - range: pat.syntax().text_range(), - kind: InlayKind::TypeHint, - label: format!("{}{}{}", LABEL_START, ty_display, LABEL_END).into(), - }); + return Some(format!("{}{}{}", LABEL_START, ty_display, LABEL_END).into()); } } @@ -412,7 +403,8 @@ mod tests { } fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) { - let ra_fixture = format!("{}\n{}", ra_fixture, FamousDefs::FIXTURE); + let ra_fixture = + format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); let (analysis, file_id) = fixture::file(&ra_fixture); let expected = extract_annotations(&*analysis.file_text(file_id).unwrap()); let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap(); @@ -422,7 +414,9 @@ mod tests { } fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) { - let (analysis, file_id) = fixture::file(ra_fixture); + let ra_fixture = + format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); + let (analysis, file_id) = fixture::file(&ra_fixture); let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap(); expect.assert_debug_eq(&inlay_hints) } @@ -854,12 +848,12 @@ fn main() { expect![[r#" [ InlayHint { - range: 147..172, + range: 148..173, kind: ChainingHint, label: "B", }, InlayHint { - range: 147..154, + range: 148..155, kind: ChainingHint, label: "A", }, @@ -920,12 +914,12 @@ fn main() { expect![[r#" [ InlayHint { - range: 143..190, + range: 144..191, kind: ChainingHint, label: "C", }, InlayHint { - range: 143..179, + range: 144..180, kind: ChainingHint, label: "B", }, @@ -965,12 +959,12 @@ fn main() { expect![[r#" [ InlayHint { - range: 246..283, + range: 247..284, kind: ChainingHint, label: "B>", }, InlayHint { - range: 246..265, + range: 247..266, kind: ChainingHint, label: "A>", }, @@ -991,7 +985,6 @@ fn main() { ); check( r#" -//- /main.rs crate:main deps:core pub struct Vec {} impl Vec { @@ -1031,7 +1024,6 @@ mod collections { fn complete_for_hint() { check( r#" -//- /main.rs crate:main deps:core pub struct Vec {} impl Vec { @@ -1078,7 +1070,6 @@ mod collections { max_length: None, }, r#" -//- /main.rs crate:main pub struct Vec {} impl Vec { @@ -1108,12 +1099,11 @@ fn main() { InlayHintsConfig { parameter_hints: false, type_hints: true, - chaining_hints: true, + chaining_hints: false, max_length: None, }, r#" -//- /main.rs crate:main deps:std -use std::iter; +use core::iter; struct MyIter; @@ -1132,12 +1122,67 @@ fn main() { fn generic(t: T) { let _x = iter::repeat(t); //^^ impl Iterator + let _chained = iter::repeat(t).take(10); + //^^^^^^^^ impl Iterator + } +} +"#, + ); + } + + #[test] + fn shorten_iterator_chaining_hints() { + check_expect( + InlayHintsConfig { + parameter_hints: false, + type_hints: false, + chaining_hints: true, + max_length: None, + }, + r#" +use core::iter; + +struct MyIter; + +impl Iterator for MyIter { + type Item = (); + fn next(&mut self) -> Option { + None } } -//- /std.rs crate:std deps:core -use core::*; +fn main() { + let _x = MyIter.by_ref() + .take(5) + .by_ref() + .take(5) + .by_ref(); +} "#, + expect![[r#" + [ + InlayHint { + range: 175..242, + kind: ChainingHint, + label: "impl Iterator", + }, + InlayHint { + range: 175..225, + kind: ChainingHint, + label: "&mut Take<&mut MyIter>", + }, + InlayHint { + range: 175..207, + kind: ChainingHint, + label: "impl Iterator", + }, + InlayHint { + range: 175..190, + kind: ChainingHint, + label: "&mut MyIter", + }, + ] + "#]], ); } } -- cgit v1.2.3 From e106857e80d1ea304b00b5ff8a3294ca9bacd959 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 7 Oct 2020 12:13:32 +0200 Subject: Shorten iterator hints for std::iter iterators behind references --- crates/assists/src/utils.rs | 2 +- crates/ide/src/inlay_hints.rs | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs index 92b3c3b00..c074b8d02 100644 --- a/crates/assists/src/utils.rs +++ b/crates/assists/src/utils.rs @@ -308,7 +308,7 @@ pub mod iter { } } } - pub(crate) mod collect { + pub(crate) mod collect { pub trait IntoIterator { type Item; } diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 279d02541..7540f56a4 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -211,7 +211,9 @@ fn hint_iterator( ty: &Type, ) -> Option { let db = sema.db; - let strukt = ty.as_adt()?; + let strukt = std::iter::successors(Some(ty.clone()), |ty| ty.remove_ref()) + .last() + .and_then(|strukt| strukt.as_adt())?; let krate = strukt.krate(db)?; if krate.declaration_name(db).as_deref() != Some("core") { return None; @@ -1169,7 +1171,7 @@ fn main() { InlayHint { range: 175..225, kind: ChainingHint, - label: "&mut Take<&mut MyIter>", + label: "impl Iterator", }, InlayHint { range: 175..207, -- cgit v1.2.3 From 783af171f74d95b498662e5168c3ba320cca8553 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 7 Oct 2020 13:14:12 +0200 Subject: Clean up inlay_hints --- crates/assists/src/utils.rs | 13 ++++++++++++- crates/ide/src/inlay_hints.rs | 32 ++++++++++++++------------------ 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs index c074b8d02..c1847f601 100644 --- a/crates/assists/src/utils.rs +++ b/crates/assists/src/utils.rs @@ -3,7 +3,7 @@ pub(crate) mod insert_use; use std::{iter, ops}; -use hir::{Adt, Crate, Enum, ScopeDef, Semantics, Trait, Type}; +use hir::{Adt, Crate, Enum, Module, ScopeDef, Semantics, Trait, Type}; use ide_db::RootDatabase; use itertools::Itertools; use rustc_hash::FxHashSet; @@ -373,6 +373,10 @@ pub use prelude::*; self.find_trait("core:iter:traits:iterator:Iterator") } + pub fn core_iter(&self) -> Option { + self.find_module("core:iter") + } + fn find_trait(&self, path: &str) -> Option { match self.find_def(path)? { hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it), @@ -387,6 +391,13 @@ pub use prelude::*; } } + fn find_module(&self, path: &str) -> Option { + match self.find_def(path)? { + hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(it)) => Some(it), + _ => None, + } + } + fn find_def(&self, path: &str) -> Option { let db = self.0.db; let mut path = path.split(':'); diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 7540f56a4..7d716577e 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -1,5 +1,5 @@ use assists::utils::FamousDefs; -use hir::{known, Adt, AssocItem, Callable, HirDisplay, Semantics, Type}; +use hir::{known, HirDisplay, Semantics}; use ide_db::RootDatabase; use stdx::to_lower_snake_case; use syntax::{ @@ -120,7 +120,7 @@ fn get_chaining_hints( return None; } if matches!(expr, ast::Expr::PathExpr(_)) { - if let Some(Adt::Struct(st)) = ty.as_adt() { + if let Some(hir::Adt::Struct(st)) = ty.as_adt() { if st.fields(sema.db).is_empty() { return None; } @@ -208,7 +208,7 @@ fn get_bind_pat_hints( fn hint_iterator( sema: &Semantics, config: &InlayHintsConfig, - ty: &Type, + ty: &hir::Type, ) -> Option { let db = sema.db; let strukt = std::iter::successors(Some(ty.clone()), |ty| ty.remove_ref()) @@ -218,17 +218,13 @@ fn hint_iterator( if krate.declaration_name(db).as_deref() != Some("core") { return None; } - // assert this type comes from `core::iter` - strukt - .module(db) - .path_to_root(db) - .into_iter() - .rev() - .find(|module| module.name(db) == Some(known::iter))?; let iter_trait = FamousDefs(sema, krate).core_iter_Iterator()?; + let iter_mod = FamousDefs(sema, krate).core_iter()?; + // assert this type comes from `core::iter` + iter_mod.visibility_of(db, &iter_trait.into()).filter(|&vis| vis == hir::Visibility::Public)?; if ty.impls_trait(db, iter_trait, &[]) { 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), + hir::AssocItem::TypeAlias(alias) if alias.name(db) == known::Item => Some(alias), _ => None, })?; if let Some(ty) = ty.normalize_trait_assoc_type(db, iter_trait, &[], assoc_type_item) { @@ -248,8 +244,8 @@ fn hint_iterator( None } -fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::IdentPat, pat_ty: &Type) -> bool { - if let Some(Adt::Enum(enum_data)) = pat_ty.as_adt() { +fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::IdentPat, pat_ty: &hir::Type) -> bool { + if let Some(hir::Adt::Enum(enum_data)) = pat_ty.as_adt() { let pat_text = bind_pat.to_string(); enum_data .variants(db) @@ -264,7 +260,7 @@ fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::IdentPat, pat_ty: &Typ fn should_not_display_type_hint( sema: &Semantics, bind_pat: &ast::IdentPat, - pat_ty: &Type, + pat_ty: &hir::Type, ) -> bool { let db = sema.db; @@ -272,7 +268,7 @@ fn should_not_display_type_hint( return true; } - if let Some(Adt::Struct(s)) = pat_ty.as_adt() { + if let Some(hir::Adt::Struct(s)) = pat_ty.as_adt() { if s.fields(db).is_empty() && s.name(db).to_string() == bind_pat.to_string() { return true; } @@ -316,7 +312,7 @@ fn should_not_display_type_hint( fn should_show_param_name_hint( sema: &Semantics, - callable: &Callable, + callable: &hir::Callable, param_name: &str, argument: &ast::Expr, ) -> bool { @@ -363,7 +359,7 @@ fn is_enum_name_similar_to_param_name( param_name: &str, ) -> bool { match sema.type_of_expr(argument).and_then(|t| t.as_adt()) { - Some(Adt::Enum(e)) => to_lower_snake_case(&e.name(sema.db).to_string()) == param_name, + Some(hir::Adt::Enum(e)) => to_lower_snake_case(&e.name(sema.db).to_string()) == param_name, _ => false, } } @@ -384,7 +380,7 @@ fn is_obvious_param(param_name: &str) -> bool { param_name.len() == 1 || is_obvious_param_name } -fn get_callable(sema: &Semantics, expr: &ast::Expr) -> Option { +fn get_callable(sema: &Semantics, expr: &ast::Expr) -> Option { match expr { ast::Expr::CallExpr(expr) => sema.type_of_expr(&expr.expr()?)?.as_callable(sema.db), ast::Expr::MethodCallExpr(expr) => sema.resolve_method_call_as_callable(expr), -- cgit v1.2.3