Open
Description
This code fails with a borrow-check error:
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:
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:
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":
| 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.
Metadata
Metadata
Assignees
Labels
Area: The borrow checkerArea: Type inferenceArea: Type systemCategory: Discussion or questions that doesn't represent real issues.Relevant to the compiler team, which will review and decide on the PR/issue.Relevant to the language teamRelevant to the types team, which will review and decide on the PR/issue.