dtolnay / async-trait

Type erasure for async trait methods
Apache License 2.0
1.81k stars 84 forks source link

Error: borrow of moved value: `self` when using let-else #224

Closed NobodyXu closed 1 year ago

NobodyXu commented 1 year ago

I encountered the following error in this file when running cargo b:

   Compiling binstalk v0.5.0 (/Users/nobodyxu/Dev/cargo-binstall/crates/binstalk)
error[E0382]: borrow of moved value: `self`
  --> crates/binstalk/src/drivers/crates_io/visitor.rs:46:42
   |
42 |     async fn visit(&mut self, entry: &mut dyn TarEntry) -> Result<(), DownloadError> {
   |                         ---- value moved here
...
46 |         let Ok(path) = path.strip_prefix(&self.manifest_dir_path)
   |                                          ^^^^^^^^^^^^^^^^^^^^^^^ value borrowed here after move
   |
   = note: move occurs because `self` has type `&mut ManifestVisitor`, which does not implement the `Copy` trait

For more information about this error, try `rustc --explain E0382`.
error: could not compile `binstalk` due to previous error

Turns out that this is a bug in async_trait codegen with let-else:

    impl TarEntriesVisitor for ManifestVisitor {
        type Target = Manifest<Meta>;
        #[allow(
            clippy::let_unit_value,
            clippy::no_effect_underscore_binding,
            clippy::shadow_same,
            clippy::type_complexity,
            clippy::type_repetition_in_bounds,
            clippy::used_underscore_binding
        )]
        fn visit<'life0, 'life1, 'async_trait>(
            &'life0 mut self,
            entry: &'life1 mut dyn TarEntry,
        ) -> ::core::pin::Pin<
            Box<
                dyn ::core::future::Future<Output = Result<(), DownloadError>>
                    + ::core::marker::Send
                    + 'async_trait,
            >,
        >
        where
            'life0: 'async_trait,
            'life1: 'async_trait,
            Self: 'async_trait,
        {
            Box::pin(async move {
                if let ::core::option::Option::Some(__ret) =
                    ::core::option::Option::None::<Result<(), DownloadError>>
                {
                    return __ret;
                }
                let mut __self = self;
                let entry = entry;
                let __ret: Result<(), DownloadError> = {
                    let path = entry.path()?;
                    let path = path.normalize();
                    let Ok (path) = path . strip_prefix (& self . manifest_dir_path) else { return Ok ((
)) } ;
                    if path == Path::new("Cargo.toml")
                        || path == Path::new("src/main.rs")
                        || path.starts_with("src/bin")
                    {
                        __self.vfs.add_path(path);
                    }
                    if path == Path::new("Cargo.toml") {
                        __self.cargo_toml_content.clear();
                        __self
                            .cargo_toml_content
                            .reserve_exact(entry.size()?.try_into().unwrap_or(usize::MAX));
                        entry.read_to_end(&mut __self.cargo_toml_content).await?;
                    }
                    Ok(())
                };
                #[allow(unreachable_code)]
                __ret
            })
        }
        /// Load binstall metadata using the extracted information stored in memory.
        fn finish(self) -> Result<Self::Target, DownloadError> {
            Ok(load_manifest(&self.cargo_toml_content, &self.vfs).map_err(io::Error::from)?)
        }
    }
dtolnay commented 1 year ago

Minimized:

use async_trait::async_trait;

#[async_trait]
pub trait Trait {
    async fn f(&mut self);
}

#[async_trait]
impl Trait for bool {
    async fn f(&mut self) {
        let true = self else { return };
    }
}
error[E0382]: use of moved value: `self`
  --> src/main.rs:11:13
   |
10 |     async fn f(&mut self) {
   |                     ---- value moved here
11 |         let true = self else { return };
   |             ^^^^ value used here after move
   |
   = note: move occurs because `self` has type `&mut bool`, which does not implement the `Copy` trait
dtolnay commented 1 year ago

This is fixed in async-trait 0.1.67.