mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-12 13:18:47 +00:00
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 <popzxc@yandex.ru>
This commit is contained in:
commit
e5f252ade7
1 changed files with 117 additions and 15 deletions
|
@ -189,7 +189,7 @@ fn get_bind_pat_hints(
|
||||||
|
|
||||||
let ty = sema.type_of_pat(&pat.clone().into())?;
|
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;
|
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(
|
fn should_not_display_type_hint(
|
||||||
db: &RootDatabase,
|
sema: &Semantics<RootDatabase>,
|
||||||
bind_pat: &ast::IdentPat,
|
bind_pat: &ast::IdentPat,
|
||||||
pat_ty: &Type,
|
pat_ty: &Type,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
let db = sema.db;
|
||||||
|
|
||||||
if pat_ty.is_unknown() {
|
if pat_ty.is_unknown() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -249,6 +251,15 @@ fn should_not_display_type_hint(
|
||||||
return it.condition().and_then(|condition| condition.pat()).is_some()
|
return it.condition().and_then(|condition| condition.pat()).is_some()
|
||||||
&& pat_is_enum_variant(db, bind_pat, pat_ty);
|
&& 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.
|
||||||
|
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)
|
||||||
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -495,19 +506,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]
|
#[test]
|
||||||
fn if_expr() {
|
fn if_expr() {
|
||||||
check(
|
check(
|
||||||
|
@ -924,4 +922,108 @@ fn main() {
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn incomplete_for_no_hint() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
let data = &[1i32, 2, 3];
|
||||||
|
//^^^^ &[i32; _]
|
||||||
|
for i
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
//- /main.rs crate:main deps:core
|
||||||
|
pub struct Vec<T> {}
|
||||||
|
|
||||||
|
impl<T> Vec<T> {
|
||||||
|
pub fn new() -> Self { Vec {} }
|
||||||
|
pub fn push(&mut self, t: T) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> IntoIterator for Vec<T> {
|
||||||
|
type Item=T;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
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<T> {}
|
||||||
|
impl<T> Vec<T> {
|
||||||
|
fn new() -> Self { Vec {} }
|
||||||
|
fn push(&mut self, t: T) { }
|
||||||
|
}
|
||||||
|
impl<T> IntoIterator for Vec<T> {
|
||||||
|
type Item=T;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn complete_for_hint() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
//- /main.rs crate:main deps:core
|
||||||
|
pub struct Vec<T> {}
|
||||||
|
|
||||||
|
impl<T> Vec<T> {
|
||||||
|
pub fn new() -> Self { Vec {} }
|
||||||
|
pub fn push(&mut self, t: T) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> IntoIterator for Vec<T> {
|
||||||
|
type Item=T;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
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<T> {}
|
||||||
|
impl<T> Vec<T> {
|
||||||
|
fn new() -> Self { Vec {} }
|
||||||
|
fn push(&mut self, t: T) { }
|
||||||
|
}
|
||||||
|
impl<T> IntoIterator for Vec<T> {
|
||||||
|
type Item=T;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue