diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-10-03 12:00:30 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-10-03 12:00:30 +0100 |
commit | e5f252ade72fee4776396122dc91a17ddc185a66 (patch) | |
tree | a9d154c1920dd03e72d83f016e77eb8b652fbbc4 | |
parent | 03dcf5111ad23700335d25ef02749666bbd08cca (diff) | |
parent | 3cadba4956bf22759803024b69b6bb67e34da576 (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.rs | 132 |
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 | ||
217 | fn should_not_display_type_hint( | 217 | fn 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#" | ||
502 | fn 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#" | ||
930 | fn 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 | ||
939 | pub struct Vec<T> {} | ||
940 | |||
941 | impl<T> Vec<T> { | ||
942 | pub fn new() -> Self { Vec {} } | ||
943 | pub fn push(&mut self, t: T) {} | ||
944 | } | ||
945 | |||
946 | impl<T> IntoIterator for Vec<T> { | ||
947 | type Item=T; | ||
948 | } | ||
949 | |||
950 | fn 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::*; | ||
961 | mod iter { | ||
962 | trait IntoIterator { | ||
963 | type Item; | ||
964 | } | ||
965 | } | ||
966 | //- /alloc.rs crate:alloc deps:core | ||
967 | mod 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 | ||
986 | pub struct Vec<T> {} | ||
987 | |||
988 | impl<T> Vec<T> { | ||
989 | pub fn new() -> Self { Vec {} } | ||
990 | pub fn push(&mut self, t: T) {} | ||
991 | } | ||
992 | |||
993 | impl<T> IntoIterator for Vec<T> { | ||
994 | type Item=T; | ||
995 | } | ||
996 | |||
997 | fn 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::*; | ||
1010 | mod iter { | ||
1011 | trait IntoIterator { | ||
1012 | type Item; | ||
1013 | } | ||
1014 | } | ||
1015 | //- /alloc.rs crate:alloc deps:core | ||
1016 | mod 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 | } |