rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
98.23k stars 12.7k forks source link

A different case of "implementation of `FnOnce` is not general enough" #129291

Open GopherJ opened 2 months ago

GopherJ commented 2 months ago

I tried this code:

async fn new_trace_lde<E: FieldElement<BaseField = Felt>>(
    &self,
    trace_info: &TraceInfo,
    main_trace: &ColMatrix<Felt>,
    domain: &StarkDomain<Felt>,
) -> (Self::TraceLde<E>, TracePolyTable<E>) {
    // Error: implementation of FnOnce is not general enough
    WebGPUTraceLde::new(trace_info, main_trace, domain, self.webgpu_hash_fn).await
}

// WebGPUTraceLde::new
pub async fn new(
    trace_info: &TraceInfo,
    main_trace: &ColMatrix<Felt>,
    domain: &StarkDomain<Felt>,
    webgpu_hash_fn: HashFn,
) -> (Self, TracePolyTable<E>) {
    // extend the main execution trace and build a Merkle tree from the extended trace
    let (main_segment_lde, main_segment_tree, main_segment_polys) =
        build_trace_commitment(main_trace, domain, webgpu_hash_fn).await;

    let trace_poly_table = TracePolyTable::new(main_segment_polys);
    let trace_lde = WebGPUTraceLde {
        main_segment_lde,
        main_segment_tree,
        aux_segment_lde: None,
        aux_segment_tree: None,
        blowup: domain.trace_to_lde_blowup(),
        trace_info: trace_info.clone(),
        webgpu_hash_fn,
    };

    (trace_lde, trace_poly_table)
}

I expected to see this happen: No error

Instead, this happened:

implementation of `FnOnce` is not general enough
closure with signature `fn(&'0 [Felt]) -> Vec<Felt>` must implement `FnOnce<(&'1 [Felt],)>`, for any two lifetimes `'0` and `'1`...
...but it actually implements `FnOnce<(&[Felt],)>` (rustc)*

Meta

rustc --version --verbose:

rustc 1.80.1 (3f5fd8dd4 2024-08-06)
binary: rustc
commit-hash: 3f5fd8dd41153bc5fdca9427e9e05be2c767ba23
commit-date: 2024-08-06
host: aarch64-apple-darwin
release: 1.80.1
LLVM version: 18.1.7

``` error: implementation of `FnOnce` is not general enough --> prover/src/gpu/webgpu/mod.rs:177:49 | 177 | ) -> (Self::TraceLde, TracePolyTable) { | _________________________________________________^ 178 | | WebGPUTraceLde::new(trace_info, main_trace, domain, self.webgpu_hash_fn).await 179 | | } | |_____^ implementation of `FnOnce` is not general enough | = note: closure with signature `fn(&'0 [Felt]) -> Vec` must implement `FnOnce<(&'1 [Felt],)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `FnOnce<(&[Felt],)>` ```

GopherJ commented 2 months ago

Reproduce steps:

  1. git clone https://github.com/GopherJ/miden-vm
  2. switch to cae2b90657430db061c617aab5af629c369ceb41
  3. go to prover/src/gpu/webgpu/mod.rs#343
  4. replace build_trace_commitment_sync::<E, Felt, H>(main_trace, domain) by build_trace_commitment(main_trace, domain, webgpu_hash_fn).await
  5. run cargo check --no-default-features --target wasm32-unknown-unknown --features webgpu in prover directory
GopherJ commented 2 months ago

Expanded code:

#[allow(
    clippy::async_yields_async,
    clippy::diverging_sub_expression,
    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 new_trace_lde<'life0, 'life1, 'life2, 'life3, 'async_trait, E>(
    &'life0 self,
    trace_info: &'life1 TraceInfo,
    main_trace: &'life2 ColMatrix<Felt>,
    domain: &'life3 StarkDomain<Felt>,
) -> ::core::pin::Pin<
    Box<
        dyn ::core::future::Future<
            Output = (Self::TraceLde<E>, TracePolyTable<E>),
        > + ::core::marker::Send + 'async_trait,
    >,
>
where
    E: 'async_trait + FieldElement<BaseField = Felt>,
    'life0: 'async_trait,
    'life1: 'async_trait,
    'life2: 'async_trait,
    'life3: 'async_trait,
    Self: 'async_trait,
{
    Box::pin(async move {
        if let ::core::option::Option::Some(__ret) = ::core::option::Option::None::<
            (Self::TraceLde<E>, TracePolyTable<E>),
        > {
            #[allow(unreachable_code)] return __ret;
        }
        let __self = self;
        let __ret: (Self::TraceLde<E>, TracePolyTable<E>) = {
            WebGPUTraceLde::new(
                    trace_info,
                    main_trace,
                    domain,
                    __self.webgpu_hash_fn,
                )
                .await
        };
        #[allow(unreachable_code)] __ret
    })