Skip to content

Commit c9e1aab

Browse files
bors[bot]lnicola
andauthored
Merge #2948
2948: Allow add_explicit_type to replace a placeholder type r=matklad a=lnicola Co-authored-by: Laurențiu Nicola <lnicola@dend.ro>
2 parents 9f58082 + e0c7ce8 commit c9e1aab

File tree

1 file changed

+48
-6
lines changed

1 file changed

+48
-6
lines changed

crates/ra_assists/src/assists/add_explicit_type.rs

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use hir::{db::HirDatabase, HirDisplay};
22
use ra_syntax::{
3-
ast::{self, AstNode, LetStmt, NameOwner},
4-
TextRange, T,
3+
ast::{self, AstNode, LetStmt, NameOwner, TypeAscriptionOwner},
4+
TextRange,
55
};
66

77
use crate::{Assist, AssistCtx, AssistId};
@@ -34,17 +34,21 @@ pub(crate) fn add_explicit_type(ctx: AssistCtx<impl HirDatabase>) -> Option<Assi
3434
// The binding must have a name
3535
let name = pat.name()?;
3636
let name_range = name.syntax().text_range();
37-
// Assist should only be applicable if cursor is between 'let' and '='
3837
let stmt_range = stmt.syntax().text_range();
3938
let eq_range = stmt.eq_token()?.text_range();
39+
// Assist should only be applicable if cursor is between 'let' and '='
4040
let let_range = TextRange::from_to(stmt_range.start(), eq_range.start());
4141
let cursor_in_range = ctx.frange.range.is_subrange(&let_range);
4242
if !cursor_in_range {
4343
return None;
4444
}
4545
// Assist not applicable if the type has already been specified
46-
if stmt.syntax().children_with_tokens().any(|child| child.kind() == T![:]) {
47-
return None;
46+
// and it has no placeholders
47+
let ascribed_ty = stmt.ascribed_type();
48+
if let Some(ref ty) = ascribed_ty {
49+
if ty.syntax().descendants().find_map(ast::PlaceholderType::cast).is_none() {
50+
return None;
51+
}
4852
}
4953
// Infer type
5054
let db = ctx.db;
@@ -60,7 +64,11 @@ pub(crate) fn add_explicit_type(ctx: AssistCtx<impl HirDatabase>) -> Option<Assi
6064
format!("Insert explicit type '{}'", ty.display(db)),
6165
|edit| {
6266
edit.target(pat_range);
63-
edit.insert(name_range.end(), format!(": {}", ty.display(db)));
67+
if let Some(ascribed_ty) = ascribed_ty {
68+
edit.replace(ascribed_ty.syntax().text_range(), format!("{}", ty.display(db)));
69+
} else {
70+
edit.insert(name_range.end(), format!(": {}", ty.display(db)));
71+
}
6472
},
6573
)
6674
}
@@ -85,6 +93,40 @@ mod tests {
8593
);
8694
}
8795

96+
#[test]
97+
fn add_explicit_type_works_for_underscore() {
98+
check_assist(
99+
add_explicit_type,
100+
"fn f() { let a<|>: _ = 1; }",
101+
"fn f() { let a<|>: i32 = 1; }",
102+
);
103+
}
104+
105+
#[test]
106+
fn add_explicit_type_works_for_nested_underscore() {
107+
check_assist(
108+
add_explicit_type,
109+
r#"
110+
enum Option<T> {
111+
Some(T),
112+
None
113+
}
114+
115+
fn f() {
116+
let a<|>: Option<_> = Option::Some(1);
117+
}"#,
118+
r#"
119+
enum Option<T> {
120+
Some(T),
121+
None
122+
}
123+
124+
fn f() {
125+
let a<|>: Option<i32> = Option::Some(1);
126+
}"#,
127+
);
128+
}
129+
88130
#[test]
89131
fn add_explicit_type_works_for_macro_call() {
90132
check_assist(

0 commit comments

Comments
 (0)