Repository: intellij-rust/intellij-rust
Issue: "Implement members" generates code that does not compile

## Environment

* **IntelliJ Rust plugin version:** 0.2.111.2147-193
* **Rust toolchain version:** 1.37.0
* **IDE name and version:** IntelliJ IDEA 2019.3

## Problem description

"Implement members" can somtimes generate code that does not compile when `Fn` is involved.

## Steps to reproduce

Write the following code:

```rust
trait Elusive {
    fn finder(&self) -> &dyn Fn(i32) -> bool;
}

struct Waldo {}

impl Elusive for Waldo {
    
}
```

Invoke "Implement members" on the trait implementation. The generated code is this:

```rust
impl Elusive for Waldo {
    fn finder(&self) -> &Fn<(i32), Output = bool> {
        unimplemented!()
    }
}
```

## Actual results

This code triggers the following diagnostics (one warning and one error):

```
warning: trait objects without an explicit `dyn` are deprecated
   |
15 |     fn finder(&self) -> &Fn<(i32), Output = bool> {
   |                          ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn Fn<(i32), Output = bool>`
   |
   = note: #[warn(bare_trait_objects)] on by default

error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead
   |
15 |     fn finder(&self) -> &Fn<(i32), Output = bool> {
   |                          ^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: for more information, see https://github.com/rust-lang/rust/issues/29625
```

## Expected results

The operation generates a signature that matches the one in the trait definition, and compiles without diagnostics:

```rust
impl Elusive for Waldo {
    fn finder(&self) -> &dyn Fn(i32) -> bool {
        unimplemented!()
    }
}
```

Changed files:
src/main/kotlin/org/rust/ide/presentation/TypeRendering.kt
src/test/kotlin/org/rust/ide/refactoring/implementMembers/ImplementMembersHandlerTest.kt

diff --git a/src/main/kotlin/org/rust/ide/presentation/TypeRendering.kt b/src/main/kotlin/org/rust/ide/presentation/TypeRendering.kt
index 35516a9b4..e36dbab64 100644
--- a/src/main/kotlin/org/rust/ide/presentation/TypeRendering.kt
+++ b/src/main/kotlin/org/rust/ide/presentation/TypeRendering.kt
@@ -7,10 +7,7 @@ package org.rust.ide.presentation
 
 import org.jetbrains.annotations.TestOnly
 import org.rust.lang.core.psi.RsTraitItem
-import org.rust.lang.core.psi.ext.RsGenericDeclaration
-import org.rust.lang.core.psi.ext.RsNamedElement
-import org.rust.lang.core.psi.ext.lifetimeParameters
-import org.rust.lang.core.psi.ext.typeParameters
+import org.rust.lang.core.psi.ext.*
 import org.rust.lang.core.types.BoundElement
 import org.rust.lang.core.types.regions.ReEarlyBound
 import org.rust.lang.core.types.regions.ReStatic
@@ -81,13 +78,7 @@ private data class TypeRenderer(
         }
 
         return when (ty) {
-            is TyFunction -> buildString {
-                ty.paramTypes.joinTo(this, ", ", "fn(", ")", transform = render)
-                if (ty.retType != TyUnit) {
-                    append(" -> ")
-                    append(render(ty.retType))
-                }
-            }
+            is TyFunction -> formatFnLike("fn", ty.paramTypes, ty.retType, render)
             is TySlice -> "[${render(ty.elementType)}]"
 
             is TyTuple -> ty.types.joinToString(", ", "(", ")", transform = render)
@@ -145,9 +136,32 @@ private data class TypeRenderer(
     private fun render(region: Region): String =
         if (region == ReUnknown) unknownLifetime else region.toString()
 
+    private fun formatFnLike(fnType: String, paramTypes: List<Ty>, retType: Ty, render: (Ty) -> String): String =
+        buildString {
+            paramTypes.joinTo(this, ", ", "$fnType(", ")", transform = render)
+            if (retType != TyUnit) {
+                append(" -> ")
+                append(render(retType))
+            }
+        }
+
     private fun formatTrait(trait: BoundElement<RsTraitItem>, render: (Ty) -> String): String = buildString {
-        append(trait.element.name ?: return anonymous)
-        if (includeTypeArguments) append(formatTraitGenerics(trait, render))
+        val name = trait.element.name ?: return anonymous
+        if (trait.element.langAttribute in listOf("fn", "fn_once", "fn_mut")) {
+            val paramTypes = trait.element.typeParameters
+                .singleOrNull()
+                ?.let { trait.subst[it] as? TyTuple }
+                ?.types
+                ?: return unknown
+            val retType = trait.assoc.entries
+                .find { it.key.name == "Output" }
+                ?.value
+                ?: TyUnit
+            append(formatFnLike(name, paramTypes, retType, render))
+        } else {
+            append(name)
+            if (includeTypeArguments) append(formatTraitGenerics(trait, render))
+        }
     }
 
     private fun formatGenerics(adt: TyAdt, render: (Ty) -> String): String {
diff --git a/src/test/kotlin/org/rust/ide/refactoring/implementMembers/ImplementMembersHandlerTest.kt b/src/test/kotlin/org/rust/ide/refactoring/implementMembers/ImplementMembersHandlerTest.kt
index 6510ec6c8..e40a6c322 100644
--- a/src/test/kotlin/org/rust/ide/refactoring/implementMembers/ImplementMembersHandlerTest.kt
+++ b/src/test/kotlin/org/rust/ide/refactoring/implementMembers/ImplementMembersHandlerTest.kt
@@ -775,6 +775,31 @@ class ImplementMembersHandlerTest : RsTestBase() {
         }
     """)
 
+    @ProjectDescriptor(WithStdlibRustProjectDescriptor::class)
+    fun `test Fn type`() = doTest("""
+        struct Foo;
+        struct Bar;
+        trait Baz {
+            fn baz(&self) -> Box<Fn(i32, i32) -> i32>;
+        }
+
+        impl Baz for Foo {
+            /*caret*/
+        }
+    """, listOf(ImplementMemberSelection("baz(&self) -> Box<Fn(i32, i32) -> i32>", true, isSelected = true)), """
+        struct Foo;
+        struct Bar;
+        trait Baz {
+            fn baz(&self) -> Box<Fn(i32, i32) -> i32>;
+        }
+
+        impl Baz for Foo {
+            fn baz(&self) -> Box<Fn(i32, i32) -> i32> {
+                unimplemented!()
+            }
+        }
+    """)
+
     fun `test pointer self type`() = doTest("""
         struct Foo;
         struct Bar;