From 8ca214fbfbd2058140764bf12005a9281a121601 Mon Sep 17 00:00:00 2001 From: Igor Aleksanov Date: Sun, 13 Sep 2020 20:24:04 +0300 Subject: Better inlay hints in 'for' loops --- crates/ide/src/inlay_hints.rs | 51 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) (limited to 'crates') diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 0afe5f8fd..60dc74d41 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -189,7 +189,7 @@ fn get_bind_pat_hints( let ty = sema.type_of_pat(&pat.clone().into())?; - if should_not_display_type_hint(sema.db, &pat, &ty) { + if should_not_display_type_hint(sema, &pat, &ty) { return None; } @@ -215,10 +215,12 @@ fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::IdentPat, pat_ty: &Typ } fn should_not_display_type_hint( - db: &RootDatabase, + sema: &Semantics, bind_pat: &ast::IdentPat, pat_ty: &Type, ) -> bool { + let db = sema.db; + if pat_ty.is_unknown() { return true; } @@ -249,6 +251,14 @@ fn should_not_display_type_hint( return it.condition().and_then(|condition| condition.pat()).is_some() && pat_is_enum_variant(db, bind_pat, pat_ty); }, + ast::ForExpr(it) => { + // We *should* display hint only if user provided "in {expr}" and we know the type of expr (and it's not unit). + // Type of expr should be iterable. + let type_is_known = |ty: Option| ty.map(|ty| !ty.is_unit() && !ty.is_unknown()).unwrap_or(false); + let should_display = it.in_token().is_some() + && it.iterable().map(|expr| type_is_known(sema.type_of_expr(&expr))).unwrap_or(false); + return !should_display; + }, _ => (), } } @@ -924,4 +934,41 @@ fn main() { "#]], ); } + + #[test] + fn incomplete_for_no_hint() { + check( + r#" +fn main() { + let data = &[1i32, 2, 3]; + //^^^^ &[i32; _] + for i +}"#, + ); + check( + r#" +fn main() { + let data = &[1i32, 2, 3]; + //^^^^ &[i32; _] + for i in + + println!("Unit expr"); +}"#, + ); + } + + #[test] + fn complete_for_hint() { + check( + r#" +fn main() { + let data = &[ 1, 2, 3 ]; + //^^^^ &[i32; _] + for i in data.into_iter() { + //^ &i32 + println!("{}", i); + } +}"#, + ); + } } -- cgit v1.2.3 From a58441ad1b87b40ddfc175e5d2c3a4d38085ef0d Mon Sep 17 00:00:00 2001 From: Igor Aleksanov Date: Sat, 3 Oct 2020 08:37:58 +0300 Subject: Make the tests for complete/incomplete for inlay hints work --- crates/ide/src/inlay_hints.rs | 87 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 77 insertions(+), 10 deletions(-) (limited to 'crates') diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 60dc74d41..b1fe33836 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -947,13 +947,46 @@ fn main() { ); check( r#" +//- /main.rs crate:main deps:core +pub struct Vec {} + +impl Vec { + pub fn new() -> Self { Vec {} } + pub fn push(&mut self, t: T) {} +} + +impl IntoIterator for Vec { + type Item=T; +} + fn main() { - let data = &[1i32, 2, 3]; - //^^^^ &[i32; _] - for i in + let mut data = Vec::new(); + //^^^^^^^^ Vec<&str> + data.push("foo"); + for i in 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 {} + impl Vec { + fn new() -> Self { Vec {} } + fn push(&mut self, t: T) { } + } + impl IntoIterator for Vec { + type Item=T; + } +} +"#, ); } @@ -961,14 +994,48 @@ fn main() { fn complete_for_hint() { check( r#" +//- /main.rs crate:main deps:core +pub struct Vec {} + +impl Vec { + pub fn new() -> Self { Vec {} } + pub fn push(&mut self, t: T) {} +} + +impl IntoIterator for Vec { + type Item=T; +} + fn main() { - let data = &[ 1, 2, 3 ]; - //^^^^ &[i32; _] - for i in data.into_iter() { - //^ &i32 - println!("{}", i); + let mut data = Vec::new(); + //^^^^^^^^ Vec<&str> + data.push("foo"); + for i in data { + //^ &str + let z = i; + //^ &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 {} + impl Vec { + fn new() -> Self { Vec {} } + fn push(&mut self, t: T) { } + } + impl IntoIterator for Vec { + type Item=T; + } +} +"#, ); } } -- cgit v1.2.3 From 91a09f50f47d451d40fe863ec4af7e2b38ed5a45 Mon Sep 17 00:00:00 2001 From: Igor Aleksanov Date: Sat, 3 Oct 2020 08:56:02 +0300 Subject: Remove 'for_expr' test from inlay_hints.rs --- crates/ide/src/inlay_hints.rs | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) (limited to 'crates') diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index b1fe33836..29f3b6828 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -505,19 +505,6 @@ fn main() { ); } - #[test] - fn for_expression() { - check( - r#" -fn main() { - let mut start = 0; - //^^^^^^^^^ i32 - for increment in 0..2 { start += increment; } - //^^^^^^^^^ i32 -}"#, - ); - } - #[test] fn if_expr() { check( @@ -963,7 +950,7 @@ fn main() { let mut data = Vec::new(); //^^^^^^^^ Vec<&str> data.push("foo"); - for i in + for i in println!("Unit expr"); } -- cgit v1.2.3 From 3cadba4956bf22759803024b69b6bb67e34da576 Mon Sep 17 00:00:00 2001 From: Igor Aleksanov Date: Sat, 3 Oct 2020 13:44:43 +0300 Subject: Improve readability in inlay_hints.rs --- crates/ide/src/inlay_hints.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'crates') diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 29f3b6828..1d7e8de56 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -254,10 +254,11 @@ fn should_not_display_type_hint( ast::ForExpr(it) => { // We *should* display hint only if user provided "in {expr}" and we know the type of expr (and it's not unit). // Type of expr should be iterable. - let type_is_known = |ty: Option| ty.map(|ty| !ty.is_unit() && !ty.is_unknown()).unwrap_or(false); - let should_display = it.in_token().is_some() - && it.iterable().map(|expr| type_is_known(sema.type_of_expr(&expr))).unwrap_or(false); - return !should_display; + return it.in_token().is_none() || + it.iterable() + .and_then(|iterable_expr|sema.type_of_expr(&iterable_expr)) + .map(|iterable_ty| iterable_ty.is_unknown() || iterable_ty.is_unit()) + .unwrap_or(true) }, _ => (), } -- cgit v1.2.3