3 ast::{self, AstNode, LetStmt, NameOwner, TypeAscriptionOwner},
7 use crate::{Assist, AssistCtx, AssistId};
9 // Assist: add_explicit_type
11 // Specify type for a let binding.
24 pub(crate) fn add_explicit_type(ctx: AssistCtx) -> Option<Assist> {
25 let stmt = ctx.find_node_at_offset::<LetStmt>()?;
26 let expr = stmt.initializer()?;
27 let pat = stmt.pat()?;
30 ast::Pat::BindPat(bind_pat) => bind_pat,
33 let pat_range = pat.syntax().text_range();
34 // The binding must have a name
35 let name = pat.name()?;
36 let name_range = name.syntax().text_range();
37 let stmt_range = stmt.syntax().text_range();
38 let eq_range = stmt.eq_token()?.text_range();
39 // Assist should only be applicable if cursor is between 'let' and '='
40 let let_range = TextRange::new(stmt_range.start(), eq_range.start());
41 let cursor_in_range = let_range.contains_range(ctx.frange.range);
45 // Assist not applicable if the type has already been specified
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() {
54 let ty = ctx.sema.type_of_expr(&expr)?;
56 if ty.contains_unknown() || ty.is_closure() {
61 let new_type_string = ty.display_truncated(db, None).to_string();
63 AssistId("add_explicit_type"),
64 format!("Insert explicit type '{}'", new_type_string),
67 if let Some(ascribed_ty) = ascribed_ty {
68 edit.replace(ascribed_ty.syntax().text_range(), new_type_string);
70 edit.insert(name_range.end(), format!(": {}", new_type_string));
80 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
83 fn add_explicit_type_target() {
84 check_assist_target(add_explicit_type, "fn f() { let a<|> = 1; }", "a");
88 fn add_explicit_type_works_for_simple_expr() {
91 "fn f() { let a<|> = 1; }",
92 "fn f() { let a<|>: i32 = 1; }",
97 fn add_explicit_type_works_for_underscore() {
100 "fn f() { let a<|>: _ = 1; }",
101 "fn f() { let a<|>: i32 = 1; }",
106 fn add_explicit_type_works_for_nested_underscore() {
116 let a<|>: Option<_> = Option::Some(1);
125 let a<|>: Option<i32> = Option::Some(1);
131 fn add_explicit_type_works_for_macro_call() {
134 r"macro_rules! v { () => {0u64} } fn f() { let a<|> = v!(); }",
135 r"macro_rules! v { () => {0u64} } fn f() { let a<|>: u64 = v!(); }",
140 fn add_explicit_type_works_for_macro_call_recursive() {
143 "macro_rules! u { () => {0u64} } macro_rules! v { () => {u!()} } fn f() { let a<|> = v!(); }",
144 "macro_rules! u { () => {0u64} } macro_rules! v { () => {u!()} } fn f() { let a<|>: u64 = v!(); }",
149 fn add_explicit_type_not_applicable_if_ty_not_inferred() {
150 check_assist_not_applicable(add_explicit_type, "fn f() { let a<|> = None; }");
154 fn add_explicit_type_not_applicable_if_ty_already_specified() {
155 check_assist_not_applicable(add_explicit_type, "fn f() { let a<|>: i32 = 1; }");
159 fn add_explicit_type_not_applicable_if_specified_ty_is_tuple() {
160 check_assist_not_applicable(add_explicit_type, "fn f() { let a<|>: (i32, i32) = (3, 4); }");
164 fn add_explicit_type_not_applicable_if_cursor_after_equals() {
165 check_assist_not_applicable(
167 "fn f() {let a =<|> match 1 {2 => 3, 3 => 5};}",
172 fn add_explicit_type_not_applicable_if_cursor_before_let() {
173 check_assist_not_applicable(
175 "fn f() <|>{let a = match 1 {2 => 3, 3 => 5};}",
180 fn closure_parameters_are_not_added() {
181 check_assist_not_applicable(
185 let multiply_by_two<|> = |i| i * 3;
186 let six = multiply_by_two(2);
192 fn default_generics_should_not_be_added() {
196 struct Test<K, T = u8> {
202 let test<|> = Test { t: 23, k: 33 };
205 struct Test<K, T = u8> {
211 let test<|>: Test<i32> = Test { t: 23, k: 33 };