about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-01-03 00:40:30 +0000
committerGitHub <noreply@github.com>2022-01-03 00:40:30 +0000
commitd89a4f0e93562a4bdf8d93abd87200731cbf731b (patch)
tree87da0ad2c8d2b69da70acaafbf846a6243b17e06
parentdf3d3d8a74e9c4780cec9f6a2bd687406dade8af (diff)
parent03291db8013b3ad75b610669538c0c8cf6639d14 (diff)
downloadrust-d89a4f0e93562a4bdf8d93abd87200731cbf731b.tar.gz
rust-d89a4f0e93562a4bdf8d93abd87200731cbf731b.zip
Merge #11173
11173: Allow adding partially resolved types r=Veykril a=SomeoneToIgnore

Sometimes when writing something like `let foo = Arc::new(Mutex::new(CrazyGenerics::new(HashMap::new())))`, I want/have to specify an explicit type for the expression.
Using turbofish isn't very readable and not always appreciated by guidelines, so `let foo: T` has to be filled.

To ease that, the PR enables the `add_explicit_type` assist on types that contain unknown types and some generics.
Fully unresolved types, arrays with unknown types and other known cases behave the same.

`_` placeholder was chosen to replace an unknown type:

```rust
let foo = HashMap::new();
// after assist usage, turns into
let foo: HashMap<_, _> = HashMap::new();
```

Co-authored-by: Kirill Bulatov <mail4score@gmail.com>
-rw-r--r--crates/hir_ty/src/display.rs22
-rw-r--r--crates/ide_assists/src/handlers/add_explicit_type.rs29
2 files changed, 47 insertions, 4 deletions
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index cd898a45d21..95d1550afc3 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -567,7 +567,27 @@ impl HirDisplay for Ty {
                     };
                     if !parameters_to_write.is_empty() {
                         write!(f, "<")?;
-                        f.write_joined(parameters_to_write, ", ")?;
+
+                        if f.display_target.is_source_code() {
+                            let mut first = true;
+                            for generic_arg in parameters_to_write {
+                                if !first {
+                                    write!(f, ", ")?;
+                                }
+                                first = false;
+
+                                if generic_arg.ty(Interner).map(|ty| ty.kind(Interner))
+                                    == Some(&TyKind::Error)
+                                {
+                                    write!(f, "_")?;
+                                } else {
+                                    generic_arg.hir_fmt(f)?;
+                                }
+                            }
+                        } else {
+                            f.write_joined(parameters_to_write, ", ")?;
+                        }
+
                         write!(f, ">")?;
                     }
                 }
diff --git a/crates/ide_assists/src/handlers/add_explicit_type.rs b/crates/ide_assists/src/handlers/add_explicit_type.rs
index 169bb0cbf4f..d7e1be900ff 100644
--- a/crates/ide_assists/src/handlers/add_explicit_type.rs
+++ b/crates/ide_assists/src/handlers/add_explicit_type.rs
@@ -60,8 +60,8 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext) -> Optio
     }
     .adjusted();
 
-    // Unresolved or unnameable types can't be annotated
-    if ty.contains_unknown() || ty.is_closure() {
+    // Fully unresolved or unnameable types can't be annotated
+    if (ty.contains_unknown() && ty.type_arguments().count() == 0) || ty.is_closure() {
         cov_mark::hit!(add_explicit_type_not_applicable_if_ty_not_inferred);
         return None;
     }
@@ -139,12 +139,35 @@ fn f() {
     }
 
     #[test]
-    fn add_explicit_type_not_applicable_unresolved() {
+    fn add_explicit_type_not_applicable_for_fully_unresolved() {
         cov_mark::check!(add_explicit_type_not_applicable_if_ty_not_inferred);
         check_assist_not_applicable(add_explicit_type, r#"fn f() { let a$0 = None; }"#);
     }
 
     #[test]
+    fn add_explicit_type_applicable_for_partially_unresolved() {
+        check_assist(
+            add_explicit_type,
+            r#"
+        struct Vec<T, V> { t: T, v: V }
+        impl<T> Vec<T, Vec<ZZZ, i32>> {
+            fn new() -> Self {
+                panic!()
+            }
+        }
+        fn f() { let a$0 = Vec::new(); }"#,
+            r#"
+        struct Vec<T, V> { t: T, v: V }
+        impl<T> Vec<T, Vec<ZZZ, i32>> {
+            fn new() -> Self {
+                panic!()
+            }
+        }
+        fn f() { let a: Vec<_, Vec<_, i32>> = Vec::new(); }"#,
+        );
+    }
+
+    #[test]
     fn add_explicit_type_not_applicable_closure_expr() {
         check_assist_not_applicable(add_explicit_type, r#"fn f() { let a$0 = || {}; }"#);
     }