Repository: intellij-rust/intellij-rust
Issue: cargo build OK but rust plugin shows error for calling clone() on &mut T

<!--
Hello and thank you for the issue!
If you would like to report a bug, we have added some points below that you can fill out.
Feel free to remove all the irrelevant text to request a new feature.
-->

## Environment

* **IntelliJ Rust plugin version:**
0.2.123.3132-201

* **Rust toolchain version:**
1.44.0

* **IDE name and version:**
PyCharm. 2020.1

* **Operating system:**
MacOS

## Problem description
Calling `clone()` on `&mut T`.  Cargo builds OK but rust plugin shows error.

## Steps to reproduce
Build the following code: 
```rust
fn dup(v: &mut Vec<u8>) -> Vec<u8> {
    v.clone()
}

fn consume(v: Vec<u8>) {
    println!("consuming v1: {:?}", v);
}

fn main() {
    let mut v1 = vec![1, 2];
    let v2 = dup(&mut v1);  
    consume(v1);
    println!("v2: {:?}", v2);
}
```
Cargo builds OK, but Line 2 `v.clone()` is marked by rust plugin as error:
```
mismatched types [E0308] expected `Vec<u8>`, found `&mut Vec<u8>` 
```

<!--
Please include as much of your codebase as needed to reproduce the error.
If the relevant files are large, please provide a link to a public repository or a [Gist](https://gist.github.com/).
-->


Changed files:
src/test/kotlin/org/rust/lang/core/type/RsExpressionTypeInferenceTest.kt, src/test/kotlin/org/rust/lang/core/type/RsStdlibExpressionTypeInferenceTest.kt, src/main/kotlin/org/rust/lang/core/resolve/RsCachedImplItem.kt, src/main/kotlin/org/rust/lang/core/stubs/StubImplementations.kt, src/main/kotlin/org/rust/lang/core/psi/ext/RsImplItem.kt

diff --git a/src/main/kotlin/org/rust/lang/core/psi/ext/RsImplItem.kt b/src/main/kotlin/org/rust/lang/core/psi/ext/RsImplItem.kt
index d4c56cbd4..df4729d18 100644
--- a/src/main/kotlin/org/rust/lang/core/psi/ext/RsImplItem.kt
+++ b/src/main/kotlin/org/rust/lang/core/psi/ext/RsImplItem.kt
@@ -16,6 +16,7 @@ import org.rust.ide.presentation.getPresentation
 import org.rust.lang.core.macros.RsExpandedElement
 import org.rust.lang.core.psi.*
 import org.rust.lang.core.psi.RsElementTypes.DEFAULT
+import org.rust.lang.core.psi.RsElementTypes.EXCL
 import org.rust.lang.core.stubs.RsImplItemStub
 import org.rust.lang.core.types.BoundElement
 import org.rust.lang.core.types.RsPsiTypeImplUtil
@@ -24,6 +25,10 @@ import org.rust.lang.core.types.ty.Ty
 val RsImplItem.default: PsiElement?
     get() = node.findChildByType(DEFAULT)?.psi
 
+/** `impl !Sync for Bar` vs `impl Foo for Bar` */
+val RsImplItem.isNegativeImpl: Boolean
+    get() = greenStub?.isNegativeImpl ?: (node.findChildByType(EXCL) != null)
+
 val RsImplItem.isReservationImpl: Boolean
     get() = queryAttributes.hasAttribute("rustc_reservation_impl")
 
diff --git a/src/main/kotlin/org/rust/lang/core/resolve/RsCachedImplItem.kt b/src/main/kotlin/org/rust/lang/core/resolve/RsCachedImplItem.kt
index 9f2e119cc..272a546da 100644
--- a/src/main/kotlin/org/rust/lang/core/resolve/RsCachedImplItem.kt
+++ b/src/main/kotlin/org/rust/lang/core/resolve/RsCachedImplItem.kt
@@ -9,10 +9,7 @@ import com.intellij.openapi.project.Project
 import org.rust.lang.core.psi.RsImplItem
 import org.rust.lang.core.psi.RsTraitItem
 import org.rust.lang.core.psi.RsTraitRef
-import org.rust.lang.core.psi.ext.RsAbstractable
-import org.rust.lang.core.psi.ext.expandedMembers
-import org.rust.lang.core.psi.ext.isReservationImpl
-import org.rust.lang.core.psi.ext.resolveToBoundTrait
+import org.rust.lang.core.psi.ext.*
 import org.rust.lang.core.psi.isValidProjectMember
 import org.rust.lang.core.resolve.ref.ResolveCacheDependency
 import org.rust.lang.core.resolve.ref.RsResolveCache
@@ -34,7 +31,7 @@ class RsCachedImplItem(
     val impl: RsImplItem
 ) {
     private val traitRef: RsTraitRef? = impl.traitRef
-    val isValid: Boolean = impl.isValidProjectMember && !impl.isReservationImpl
+    val isValid: Boolean = impl.isValidProjectMember && !impl.isReservationImpl && !impl.isNegativeImpl
     val isInherent: Boolean get() = traitRef == null
 
     val implementedTrait: BoundElement<RsTraitItem>? by lazy(PUBLICATION) { traitRef?.resolveToBoundTrait() }
diff --git a/src/main/kotlin/org/rust/lang/core/stubs/StubImplementations.kt b/src/main/kotlin/org/rust/lang/core/stubs/StubImplementations.kt
index 1e64888a3..e43ed070e 100644
--- a/src/main/kotlin/org/rust/lang/core/stubs/StubImplementations.kt
+++ b/src/main/kotlin/org/rust/lang/core/stubs/StubImplementations.kt
@@ -49,7 +49,7 @@ class RsFileStub : PsiFileStubImpl<RsFile> {
     override fun getType() = Type
 
     object Type : IStubFileElementType<RsFileStub>(RsLanguage) {
-        private const val STUB_VERSION = 200
+        private const val STUB_VERSION = 201
 
         // Bump this number if Stub structure changes
         override fun getStubVersion(): Int = RustParserDefinition.PARSER_VERSION + STUB_VERSION
@@ -618,6 +618,10 @@ class RsImplItemStub(
     parent: StubElement<*>?, elementType: IStubElementType<*, *>,
     override val flags: Int
 ) : RsAttributeOwnerStubBase<RsImplItem>(parent, elementType) {
+
+    val isNegativeImpl: Boolean
+        get() = BitUtil.isSet(flags, NEGATIVE_IMPL_MASK)
+
     object Type : RsStubElementType<RsImplItemStub, RsImplItem>("IMPL_ITEM") {
 
         override fun deserialize(dataStream: StubInputStream, parentStub: StubElement<*>?) =
@@ -630,11 +634,18 @@ class RsImplItemStub(
         override fun createPsi(stub: RsImplItemStub): RsImplItem =
             RsImplItemImpl(stub, this)
 
-        override fun createStub(psi: RsImplItem, parentStub: StubElement<*>?) =
-            RsImplItemStub(parentStub, this, RsAttributeOwnerStub.extractFlags(psi))
+        override fun createStub(psi: RsImplItem, parentStub: StubElement<*>?): RsImplItemStub {
+            var flags = RsAttributeOwnerStub.extractFlags(psi)
+            flags = BitUtil.set(flags, NEGATIVE_IMPL_MASK, psi.isNegativeImpl)
+            return RsImplItemStub(parentStub, this, flags)
+        }
 
         override fun indexStub(stub: RsImplItemStub, sink: IndexSink) = sink.indexImplItem(stub)
     }
+
+    companion object {
+        private val NEGATIVE_IMPL_MASK: Int = makeBitMask(RsAttributeOwnerStub.USED_BITS + 0)
+    }
 }
 
 
diff --git a/src/test/kotlin/org/rust/lang/core/type/RsExpressionTypeInferenceTest.kt b/src/test/kotlin/org/rust/lang/core/type/RsExpressionTypeInferenceTest.kt
index 386356390..bc7067bb8 100644
--- a/src/test/kotlin/org/rust/lang/core/type/RsExpressionTypeInferenceTest.kt
+++ b/src/test/kotlin/org/rust/lang/core/type/RsExpressionTypeInferenceTest.kt
@@ -1522,4 +1522,17 @@ class RsExpressionTypeInferenceTest : RsTypificationTestBase() {
           //^ <unknown>
         }
     """)
+
+    fun `test negative impl is ignored`() = testExpr("""
+        struct S;
+        trait Clone: Sized { fn clone(&self) -> Self { unimplemented!() } }
+        impl Clone for S {}
+        impl !Clone for &mut S {}
+        fn main() {
+            let a = &mut S;
+            let b = a.clone();
+            b;
+          //^ S
+        }
+    """)
 }
diff --git a/src/test/kotlin/org/rust/lang/core/type/RsStdlibExpressionTypeInferenceTest.kt b/src/test/kotlin/org/rust/lang/core/type/RsStdlibExpressionTypeInferenceTest.kt
index 75a97fb61..8a6835f71 100644
--- a/src/test/kotlin/org/rust/lang/core/type/RsStdlibExpressionTypeInferenceTest.kt
+++ b/src/test/kotlin/org/rust/lang/core/type/RsStdlibExpressionTypeInferenceTest.kt
@@ -795,4 +795,17 @@ class RsStdlibExpressionTypeInferenceTest : RsTypificationTestBase() {
             a;
         } //^ i32
     """)
+
+    // There is `impl<T: ?Sized> !Clone for &mut T {}`
+    fun `test clone through mut ref`() = stubOnlyTypeInfer("""
+    //- main.rs
+        #[derive(Clone)]
+        pub struct S;
+
+        fn main() {
+            let a = &mut S;
+            let b = a.clone();
+            b;
+        } //^ S
+    """)
 }