Closed
Description
I tried this code:
ambaxter/bbolt-rs@69eb00a#diff-4007187965c1fea4fd252a76f5f1007b2ea59f6d86e2f454edee547c5036be24R20
I expected to see this happen: Code compilation, or at least a sensible error.
Instead, this happened:
error[E0596]: cannot borrow `*f` as mutable, as it is a captured variable in a `Fn` closure
--> src/util.rs:20:17
|
14 | fn walk<F>(src: &Bolt, f: &mut F) -> crate::Result<()>
| ---- ----------------- change this to return `FnMut` instead of `Fn`
...
18 | src.view(|tx| {
| ---- in this closure
19 | let tx_root = Breadcrumb::Root(b"tx".as_slice());
20 | tx.for_each(|name, b| walk_bucket(&b, &tx_root, name, None, b.sequence(), f))
| ^^^^^^^^^ cannot borrow as mutable - mutable borrow occurs due to use of `*f` in closure
For more information about this error, try `rustc --explain E0596`.
I tried to make a reproducer using the following code that expresses the same type and fn signatures on Rust Playground, but I'm unable to trigger it.
#![allow(dead_code)]
#![allow(unused_variables)]
use std::marker::PhantomData;
type Result<T, E = String> = std::result::Result<T, E>;
struct Bolt {}
trait BoltApi {
fn view<'tx, F: FnMut(TxRef<'tx>) -> crate::Result<()>>(&'tx self, f: F) -> crate::Result<()>;
}
impl BoltApi for Bolt {
fn view<'tx, F: FnMut(TxRef<'tx>) -> crate::Result<()>>(
&'tx self,
mut f: F,
) -> crate::Result<()> {
Ok(())
}
}
struct BucketImpl<'tx> {
_tx: PhantomData<&'tx u64>,
}
trait BucketApi<'tx> {
fn for_each<F: FnMut(&'tx [u8], Option<&'tx [u8]>) -> crate::Result<()>>(
&self,
f: F,
) -> crate::Result<()>;
}
impl<'tx> BucketApi<'tx> for BucketImpl<'tx> {
fn for_each<F: FnMut(&'tx [u8], Option<&'tx [u8]>) -> crate::Result<()>>(
&self,
f: F,
) -> crate::Result<()> {
Ok(())
}
}
struct TxRef<'tx> {
_tx: PhantomData<&'tx u64>,
}
trait TxApi<'tx> {
fn for_each<F: FnMut(&[u8], BucketImpl<'tx>) -> crate::Result<()>>(
&self,
f: F,
) -> crate::Result<()>;
}
impl<'tx> TxApi<'tx> for TxRef<'tx> {
fn for_each<F: FnMut(&[u8], BucketImpl<'tx>) -> crate::Result<()>>(
&self,
f: F,
) -> crate::Result<()>
where {
Ok(())
}
}
struct Tx {}
fn walk<F: FnMut(&[u8], Option<&[u8]>, u64) -> crate::Result<()>>(
src: &Bolt,
f: &mut F,
) -> crate::Result<()> {
src.view(|tx| tx.for_each(|name, b| tx.for_each(|k, v| walk_bucket(&b, k, None, 0, f))))
}
fn walk_bucket<F: FnMut(&[u8], Option<&[u8]>, u64) -> crate::Result<()>>(
b: &BucketImpl,
key: &[u8],
value: Option<&[u8]>,
seq: u64,
f: &mut F,
) -> crate::Result<()> {
f(key, value, seq)?;
b.for_each(|k, v| walk_bucket(b, k, v, 0, f))
}
fn main() {}
Meta
rustc --version --verbose
:
% rustc --version --verbose
rustc 1.78.0 (9b00956e5 2024-04-29)
binary: rustc
commit-hash: 9b00956e56009bab2aa15d7bff10916599e3d6d6
commit-date: 2024-04-29
host: x86_64-apple-darwin
release: 1.78.0
LLVM version: 18.1.2
tested on Nightly as well.
Backtrace
% RUST_BACKTRACE=1 cargo build
Compiling bbolt-rs v1.3.9 (/Users/abaxter/RustroverProjects/bucket_test)
warning: unused import: `crate::common::cell::RefCell`
--> src/common/pool.rs:1:5
|
1 | use crate::common::cell::RefCell;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(unused_imports)]` on by default
warning: unused import: `std::rc::Rc`
--> src/common/pool.rs:6:5
|
6 | use std::rc::Rc;
| ^^^^^^^^^^^
warning: unused import: `size::Size`
--> src/util.rs:3:5
|
3 | use size::Size;
| ^^^^^^^^^^
warning: unused import: `DerefMut`
--> src/bucket.rs:24:34
|
24 | use std::ops::{AddAssign, Deref, DerefMut};
| ^^^^^^^^
warning: unused import: `std::io::Write`
--> src/tx.rs:28:5
|
28 | use std::io::Write;
| ^^^^^^^^^^^^^^
warning: unused variable: `size`
--> src/util.rs:9:11
|
9 | let mut size = 0u64;
| ^^^^ help: if this is intentional, prefix it with an underscore: `_size`
|
= note: `#[warn(unused_variables)]` on by default
warning: unused variable: `dst_tx`
--> src/util.rs:10:11
|
10 | let mut dst_tx = dst.begin_rw_tx()?;
| ^^^^^^ help: if this is intentional, prefix it with an underscore: `_dst_tx`
warning: unused variable: `max_size`
--> src/util.rs:7:44
|
7 | pub fn compact(src: &Bolt, dst: &mut Bolt, max_size: u64) -> crate::Result<()> {
| ^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_max_size`
warning: variable does not need to be mutable
--> src/util.rs:9:7
|
9 | let mut size = 0u64;
| ----^^^^
| |
| help: remove this `mut`
|
= note: `#[warn(unused_mut)]` on by default
warning: variable does not need to be mutable
--> src/util.rs:10:7
|
10 | let mut dst_tx = dst.begin_rw_tx()?;
| ----^^^^^^
| |
| help: remove this `mut`
error[E0596]: cannot borrow `*f` as mutable, as it is a captured variable in a `Fn` closure
--> src/util.rs:20:17
|
14 | fn walk<F>(src: &Bolt, f: &mut F) -> crate::Result<()>
| ---- ----------------- change this to return `FnMut` instead of `Fn`
...
18 | src.view(|tx| {
| ---- in this closure
19 | let tx_root = Breadcrumb::Root(b"tx".as_slice());
20 | tx.for_each(|name, b| walk_bucket(&b, &tx_root, name, None, b.sequence(), f))
| ^^^^^^^^^ cannot borrow as mutable - mutable borrow occurs due to use of `*f` in closure
For more information about this error, try `rustc --explain E0596`.
warning: `bbolt-rs` (lib) generated 10 warnings
error: could not compile `bbolt-rs` (lib) due to 1 previous error; 10 warnings emitted