Repository: rust
Issue: Fully-qualifying a `From::from` call adds an implicit reborrow that is not inferred otherwise
Labels: A-type-system,A-borrow-checker,T-lang,T-compiler,A-inference,C-discussion,T-types

This code fails with a borrow-check error:

```rust
struct Foo;

impl<'a> From<&'a mut Foo> for () {
    fn from(_: &'a mut Foo) -> () {}
}

fn main() {
    let mut foo = Foo;
    let foo_mut = &mut foo;

    <()>::from(foo_mut);
    <()>::from(foo_mut);
}
```

```
error[E0382]: use of moved value: `foo_mut`
  --> src/main.rs:12:16
   |
9  |     let foo_mut = &mut foo;
   |         ------- move occurs because `foo_mut` has type `&mut Foo`, which does not implement the `Copy` trait
10 | 
11 |     <()>::from(foo_mut);
   |                ------- value moved here
12 |     <()>::from(foo_mut);
   |                ^^^^^^^ value used here after move

For more information about this error, try `rustc --explain E0382`.
```

However, explicitly specifying `<() as From<&mut Foo>>` in the first call causes compilation to succeed:

```rust
struct Foo;

impl<'a> From<&'a mut Foo> for () {
    fn from(_: &'a mut Foo) -> () {}
}

fn main() {
    let mut foo = Foo;
    let foo_mut = &mut foo;

    <() as From<&mut Foo>>::from(foo_mut);
    <()>::from(foo_mut);
}
```

Comparing the MIR output for the two versions, it appears that the fully-qualified version reborrows from `foo_mut`, whereas the unqualified version does not:

```diff
     bb0: {
-        StorageLive(_1);                 // scope 0 at unqual.rs:10:9: 10:16
-        _1 = Foo;                        // scope 0 at unqual.rs:10:19: 10:22
-        FakeRead(ForLet(None), _1);      // scope 0 at unqual.rs:10:9: 10:16
-        StorageLive(_2);                 // scope 1 at unqual.rs:11:9: 11:16
-        _2 = &mut _1;                    // scope 1 at unqual.rs:11:19: 11:27
-        FakeRead(ForLet(None), _2);      // scope 1 at unqual.rs:11:9: 11:16
-        StorageLive(_3);                 // scope 2 at unqual.rs:13:5: 13:24
-        StorageLive(_4);                 // scope 2 at unqual.rs:13:16: 13:23
-        _4 = move _2;                    // scope 2 at unqual.rs:13:16: 13:23
-        _3 = <() as From<&mut Foo>>::from(move _4) -> [return: bb1, unwind: bb3]; // scope 2 at unqual.rs:13:5: 13:24
+        StorageLive(_1);                 // scope 0 at fqs.rs:10:9: 10:16
+        _1 = Foo;                        // scope 0 at fqs.rs:10:19: 10:22
+        FakeRead(ForLet(None), _1);      // scope 0 at fqs.rs:10:9: 10:16
+        StorageLive(_2);                 // scope 1 at fqs.rs:11:9: 11:16
+        _2 = &mut _1;                    // scope 1 at fqs.rs:11:19: 11:27
+        FakeRead(ForLet(None), _2);      // scope 1 at fqs.rs:11:9: 11:16
+        StorageLive(_3);                 // scope 2 at fqs.rs:13:5: 13:42
+        StorageLive(_4);                 // scope 2 at fqs.rs:13:34: 13:41
+        _4 = &mut (*_2);                 // scope 2 at fqs.rs:13:34: 13:41
+        _3 = <() as From<&mut Foo>>::from(move _4) -> [return: bb1, unwind: bb3]; // scope 2 at fqs.rs:13:5: 13:42
                                          // mir::Constant
-                                         // + span: unqual.rs:13:5: 13:15
+                                         // + span: fqs.rs:13:5: 13:33
                                          // + user_ty: UserType(0)
                                          // + literal: Const { ty: fn(&mut Foo) {<() as std::convert::From<&mut Foo>>::from}, val: Value(Scalar(<ZST>)) }
     }
```

I'm guessing this reborrow is due to, or at least related to, the following change in "User Type Annotations":

```diff
 | User Type Annotations
-| 0: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: TypeOf(DefId(2:2912 ~ core[f488]::convert::From::from), UserSubsts { substs: [(), ^0], user_self_ty: None }) } at unqual.rs:13:5: 13:15
-| 1: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: TypeOf(DefId(2:2912 ~ core[f488]::convert::From::from), UserSubsts { substs: [(), ^0], user_self_ty: None }) } at unqual.rs:14:5: 14:15
+| 0: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: TypeOf(DefId(2:2912 ~ core[f488]::convert::From::from), UserSubsts { substs: [(), &mut Foo], user_self_ty: None }) } at fqs.rs:13:5: 13:33
+| 1: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: TypeOf(DefId(2:2912 ~ core[f488]::convert::From::from), UserSubsts { substs: [(), ^0], user_self_ty: None }) } at fqs.rs:14:5: 14:15
```

In the unqualified `<()>::from(...)` version, `From::from`'s type seems to be generic over a type parameter, while in the qualified `<() as From<&mut Foo>>::from(...)` version, `From::from`'s type is generic over a lifetime.

*See also [this Zulip thread](https://rust-lang.zulipchat.com/#narrow/stream/122651-general/topic/Noob.20question.20about.20moving.20semantics).*