aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-10-03 12:00:30 +0100
committerGitHub <[email protected]>2020-10-03 12:00:30 +0100
commite5f252ade72fee4776396122dc91a17ddc185a66 (patch)
treea9d154c1920dd03e72d83f016e77eb8b652fbbc4
parent03dcf5111ad23700335d25ef02749666bbd08cca (diff)
parent3cadba4956bf22759803024b69b6bb67e34da576 (diff)
Merge #5997
5997: Better inlay hints in 'for' loops r=popzxc a=popzxc For #5206 (one part of the fix). This PR refines the logic of spawning an inlay hints in `for` loops. We only must provide a hint if the following criteria are met: - User already typed `in` keyword. - Type of expression is known and it's not unit. **However:** I don't know why, but I was unable to make `complete_for_hint` test work. Either without or with my changes, I was always getting this test failed because no hint was spawned for the loop variable. This change works locally, so I would really appreciate an explanation why this test isn't working now and how to fix it. ![image](https://user-images.githubusercontent.com/12111581/93024580-41a53380-f600-11ea-9bb1-1f8ac141be95.png) Co-authored-by: Igor Aleksanov <[email protected]>
-rw-r--r--crates/ide/src/inlay_hints.rs132
1 files changed, 117 insertions, 15 deletions
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 0afe5f8fd..1d7e8de56 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -189,7 +189,7 @@ fn get_bind_pat_hints(
189 189
190 let ty = sema.type_of_pat(&pat.clone().into())?; 190 let ty = sema.type_of_pat(&pat.clone().into())?;
191 191
192 if should_not_display_type_hint(sema.db, &pat, &ty) { 192 if should_not_display_type_hint(sema, &pat, &ty) {
193 return None; 193 return None;
194 } 194 }
195 195
@@ -215,10 +215,12 @@ fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::IdentPat, pat_ty: &Typ
215} 215}
216 216
217fn should_not_display_type_hint( 217fn should_not_display_type_hint(
218 db: &RootDatabase, 218 sema: &Semantics<RootDatabase>,
219 bind_pat: &ast::IdentPat, 219 bind_pat: &ast::IdentPat,
220 pat_ty: &Type, 220 pat_ty: &Type,
221) -> bool { 221) -> bool {
222 let db = sema.db;
223
222 if pat_ty.is_unknown() { 224 if pat_ty.is_unknown() {
223 return true; 225 return true;
224 } 226 }
@@ -249,6 +251,15 @@ fn should_not_display_type_hint(
249 return it.condition().and_then(|condition| condition.pat()).is_some() 251 return it.condition().and_then(|condition| condition.pat()).is_some()
250 && pat_is_enum_variant(db, bind_pat, pat_ty); 252 && pat_is_enum_variant(db, bind_pat, pat_ty);
251 }, 253 },
254 ast::ForExpr(it) => {
255 // We *should* display hint only if user provided "in {expr}" and we know the type of expr (and it's not unit).
256 // Type of expr should be iterable.
257 return it.in_token().is_none() ||
258 it.iterable()
259 .and_then(|iterable_expr|sema.type_of_expr(&iterable_expr))
260 .map(|iterable_ty| iterable_ty.is_unknown() || iterable_ty.is_unit())
261 .unwrap_or(true)
262 },
252 _ => (), 263 _ => (),
253 } 264 }
254 } 265 }
@@ -496,19 +507,6 @@ fn main() {
496 } 507 }
497 508
498 #[test] 509 #[test]
499 fn for_expression() {
500 check(
501 r#"
502fn main() {
503 let mut start = 0;
504 //^^^^^^^^^ i32
505 for increment in 0..2 { start += increment; }
506 //^^^^^^^^^ i32
507}"#,
508 );
509 }
510
511 #[test]
512 fn if_expr() { 510 fn if_expr() {
513 check( 511 check(
514 r#" 512 r#"
@@ -924,4 +922,108 @@ fn main() {
924 "#]], 922 "#]],
925 ); 923 );
926 } 924 }
925
926 #[test]
927 fn incomplete_for_no_hint() {
928 check(
929 r#"
930fn main() {
931 let data = &[1i32, 2, 3];
932 //^^^^ &[i32; _]
933 for i
934}"#,
935 );
936 check(
937 r#"
938//- /main.rs crate:main deps:core
939pub struct Vec<T> {}
940
941impl<T> Vec<T> {
942 pub fn new() -> Self { Vec {} }
943 pub fn push(&mut self, t: T) {}
944}
945
946impl<T> IntoIterator for Vec<T> {
947 type Item=T;
948}
949
950fn main() {
951 let mut data = Vec::new();
952 //^^^^^^^^ Vec<&str>
953 data.push("foo");
954 for i in
955
956 println!("Unit expr");
957}
958
959//- /core.rs crate:core
960#[prelude_import] use iter::*;
961mod iter {
962 trait IntoIterator {
963 type Item;
964 }
965}
966//- /alloc.rs crate:alloc deps:core
967mod collections {
968 struct Vec<T> {}
969 impl<T> Vec<T> {
970 fn new() -> Self { Vec {} }
971 fn push(&mut self, t: T) { }
972 }
973 impl<T> IntoIterator for Vec<T> {
974 type Item=T;
975 }
976}
977"#,
978 );
979 }
980
981 #[test]
982 fn complete_for_hint() {
983 check(
984 r#"
985//- /main.rs crate:main deps:core
986pub struct Vec<T> {}
987
988impl<T> Vec<T> {
989 pub fn new() -> Self { Vec {} }
990 pub fn push(&mut self, t: T) {}
991}
992
993impl<T> IntoIterator for Vec<T> {
994 type Item=T;
995}
996
997fn main() {
998 let mut data = Vec::new();
999 //^^^^^^^^ Vec<&str>
1000 data.push("foo");
1001 for i in data {
1002 //^ &str
1003 let z = i;
1004 //^ &str
1005 }
1006}
1007
1008//- /core.rs crate:core
1009#[prelude_import] use iter::*;
1010mod iter {
1011 trait IntoIterator {
1012 type Item;
1013 }
1014}
1015//- /alloc.rs crate:alloc deps:core
1016mod collections {
1017 struct Vec<T> {}
1018 impl<T> Vec<T> {
1019 fn new() -> Self { Vec {} }
1020 fn push(&mut self, t: T) { }
1021 }
1022 impl<T> IntoIterator for Vec<T> {
1023 type Item=T;
1024 }
1025}
1026"#,
1027 );
1028 }
927} 1029}