Repository: intellij-rust/intellij-rust
Issue: IllegalStateException in `ConvertToTyUsingFromTraitFix`

IllegalStateException is thrown when `ConvertToTyUsingFromTraitFix` is invoked on types that cannot be parsed as paths (e.g. `&[u8]`).

```
java.lang.IllegalStateException: Failed to create RsCallExpr from `&[u8]::from(x)`
	at org.rust.lang.core.psi.RsPsiFactory.createAssocFunctionCall(RsPsiFactory.kt:672)
	at org.rust.ide.annotator.fixes.ConvertToTyUsingFromTraitFix.invoke(ConvertToTyUsingFromTraitFix.kt:28)
```

Changed files:
src/test/kotlin/org/rust/ide/inspections/typecheck/ConvertToTyUsingFromTraitFixTest.kt
src/main/kotlin/org/rust/ide/annotator/fixes/ConvertToTyUsingFromTraitFix.kt
src/main/kotlin/org/rust/lang/core/psi/RsPsiFactory.kt

diff --git a/src/main/kotlin/org/rust/ide/annotator/fixes/ConvertToTyUsingFromTraitFix.kt b/src/main/kotlin/org/rust/ide/annotator/fixes/ConvertToTyUsingFromTraitFix.kt
index 80a43e911..c2b54a98b 100644
--- a/src/main/kotlin/org/rust/ide/annotator/fixes/ConvertToTyUsingFromTraitFix.kt
+++ b/src/main/kotlin/org/rust/ide/annotator/fixes/ConvertToTyUsingFromTraitFix.kt
@@ -23,8 +23,20 @@ class ConvertToTyUsingFromTraitFix(expr: PsiElement, val ty: Ty) : LocalQuickFix
 
     override fun getText(): String = "Convert to $ty using `From` trait"
 
-    override fun invoke(project: Project, file: PsiFile, editor: Editor?, startElement: PsiElement, endElement: PsiElement) {
+    override fun invoke(
+        project: Project,
+        file: PsiFile,
+        editor: Editor?,
+        startElement: PsiElement,
+        endElement: PsiElement
+    ) {
         if (startElement !is RsExpr) return
-        startElement.replace(RsPsiFactory(project).createAssocFunctionCall(tyToStringWithoutTypeArgs(ty), "from", listOf(startElement)))
+
+        val newElement = RsPsiFactory(project).createAssocFunctionCall(
+            tyToStringWithoutTypeArgs(ty),
+            "from",
+            listOf(startElement)
+        )
+        startElement.replace(newElement)
     }
 }
diff --git a/src/main/kotlin/org/rust/lang/core/psi/RsPsiFactory.kt b/src/main/kotlin/org/rust/lang/core/psi/RsPsiFactory.kt
index 123b929d1..7d37ed1de 100644
--- a/src/main/kotlin/org/rust/lang/core/psi/RsPsiFactory.kt
+++ b/src/main/kotlin/org/rust/lang/core/psi/RsPsiFactory.kt
@@ -430,8 +430,11 @@ class RsPsiFactory(
     fun createFunctionCall(functionName: String, arguments: Iterable<RsExpr>): RsCallExpr =
         createExpressionOfType("$functionName(${arguments.joinToString { it.text }})")
 
-    fun createAssocFunctionCall(typeText: String, methodNameText: String, arguments: Iterable<RsExpr>): RsCallExpr =
-        createExpressionOfType("$typeText::$methodNameText(${arguments.joinToString { it.text }})")
+    fun createAssocFunctionCall(typeText: String, methodNameText: String, arguments: Iterable<RsExpr>): RsCallExpr {
+        val isCorrectTypePath = tryCreatePath(typeText) != null
+        val typePath = if (isCorrectTypePath) typeText else "<$typeText>"
+        return createExpressionOfType("$typePath::$methodNameText(${arguments.joinToString { it.text }})")
+    }
 
     fun createNoArgsMethodCall(expr: RsExpr, methodNameText: String): RsDotExpr = when (expr) {
         is RsBinaryExpr, is RsUnaryExpr, is RsCastExpr -> createExpressionOfType("(${expr.text}).$methodNameText()")
diff --git a/src/test/kotlin/org/rust/ide/inspections/typecheck/ConvertToTyUsingFromTraitFixTest.kt b/src/test/kotlin/org/rust/ide/inspections/typecheck/ConvertToTyUsingFromTraitFixTest.kt
index a5a4b50b2..a47b47f62 100644
--- a/src/test/kotlin/org/rust/ide/inspections/typecheck/ConvertToTyUsingFromTraitFixTest.kt
+++ b/src/test/kotlin/org/rust/ide/inspections/typecheck/ConvertToTyUsingFromTraitFixTest.kt
@@ -13,38 +13,37 @@ import org.rust.ide.inspections.RsTypeCheckInspection
 @ProjectDescriptor(WithStdlibRustProjectDescriptor::class)
 class ConvertToTyUsingFromTraitFixTest : RsInspectionsTestBase(RsTypeCheckInspection::class) {
     fun `test B from A when impl From A for B is available`() = checkFixByText("Convert to B using `From` trait", """
-        struct A{}
-        struct B{}
+        struct A;
+        struct B;
 
-        impl From<A> for B { fn from(item: A) -> Self {B{}} }
+        impl From<A> for B { fn from(item: A) -> Self { B } }
 
         fn main () {
-            let b: B = <error>A {}<caret></error>;
+            let b: B = <error>A<caret></error>;
         }
     """, """
-        struct A{}
-        struct B{}
+        struct A;
+        struct B;
 
-        impl From<A> for B { fn from(item: A) -> Self {B{}} }
+        impl From<A> for B { fn from(item: A) -> Self { B } }
 
         fn main () {
-            let b: B = B::from(A {});
+            let b: B = B::from(A);
         }
     """)
 
     fun `test no fix when impl From A for B is not available`() = checkFixIsUnavailable("Convert to B using `From` trait", """
-        struct A{}
-        struct B{}
-        struct C{}
+        struct A;
+        struct B;
+        struct C;
 
-        impl From<A> for C { fn from(item: A) -> Self {C{}} }
+        impl From<A> for C { fn from(item: A) -> Self { C } }
 
         fn main () {
-            let b: B = <error>A {}<caret></error>;
+            let b: B = <error>A<caret></error>;
         }
     """)
 
-
     fun `test From impl provided by std lib`() = checkFixByText("Convert to u32 using `From` trait", """
         fn main () {
             let x: u32 = <error>'X'<caret></error>;
@@ -65,4 +64,43 @@ class ConvertToTyUsingFromTraitFixTest : RsInspectionsTestBase(RsTypeCheckInspec
         }
     """)
 
+    fun `test From impl for reference type`() = checkFixByText(
+        "Convert to &[u8] using `From` trait", """
+        struct A;
+        
+        impl From<A> for &[u8] { fn from(item: A) -> Self { &[] } }
+        
+        fn main() {
+            let b: &[u8] = <error>A<caret></error>;
+        }
+    """, """
+        struct A;
+        
+        impl From<A> for &[u8] { fn from(item: A) -> Self { &[] } }
+        
+        fn main() {
+            let b: &[u8] = <&[u8]>::from(A);
+        }
+    """
+    )
+
+    fun `test From impl for tuple type`() = checkFixByText(
+        "Convert to (i32, i32) using `From` trait", """
+        struct A;
+        
+        impl From<A> for (i32, i32) { fn from(item: A) -> Self { (0, 0) } }
+        
+        fn main() {
+            let b: (i32, i32) = <error>A<caret></error>;
+        }
+    """, """
+        struct A;
+        
+        impl From<A> for (i32, i32) { fn from(item: A) -> Self { (0, 0) } }
+        
+        fn main() {
+            let b: (i32, i32) = <(i32, i32)>::from(A);
+        }
+    """
+    )
 }