Skip to content

Commit e5f252a

Browse files
bors[bot]popzxc
andauthored
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]>
2 parents 03dcf51 + 3cadba4 commit e5f252a

File tree

1 file changed

+117
-15
lines changed

1 file changed

+117
-15
lines changed

crates/ide/src/inlay_hints.rs

+117-15
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ fn get_bind_pat_hints(
189189

190190
let ty = sema.type_of_pat(&pat.clone().into())?;
191191

192-
if should_not_display_type_hint(sema.db, &pat, &ty) {
192+
if should_not_display_type_hint(sema, &pat, &ty) {
193193
return None;
194194
}
195195

@@ -215,10 +215,12 @@ fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::IdentPat, pat_ty: &Typ
215215
}
216216

217217
fn should_not_display_type_hint(
218-
db: &RootDatabase,
218+
sema: &Semantics<RootDatabase>,
219219
bind_pat: &ast::IdentPat,
220220
pat_ty: &Type,
221221
) -> bool {
222+
let db = sema.db;
223+
222224
if pat_ty.is_unknown() {
223225
return true;
224226
}
@@ -249,6 +251,15 @@ fn should_not_display_type_hint(
249251
return it.condition().and_then(|condition| condition.pat()).is_some()
250252
&& pat_is_enum_variant(db, bind_pat, pat_ty);
251253
},
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+
},
252263
_ => (),
253264
}
254265
}
@@ -495,19 +506,6 @@ fn main() {
495506
);
496507
}
497508

498-
#[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-
511509
#[test]
512510
fn if_expr() {
513511
check(
@@ -924,4 +922,108 @@ fn main() {
924922
"#]],
925923
);
926924
}
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+
}
9271029
}

0 commit comments

Comments
 (0)