Rustc complains about unsatisfied trait bounds that should be fulfilled

⚓ Rust    📅 2026-02-23    👤 surdeus    👁️ 4      

surdeus

I have a problem in one of my projects where the Rust compiler complains about unsatisfied trait bounds. I tried to create an MRE, but was unsuccessful until now, because of the plethora of dependencies and unavailability of some third-party crates on play.rust-lang.org.

The error in question arises here:

   Compiling ezsp-fwupd v1.0.0 (/home/neumann/RustroverProjects/ezsp-fwupd/ezsp-fwupd)
error[E0599]: the method `launch_standalone_bootloader` exists for struct `Uart<tokio::sync::mpsc::Sender<ashv2::actor::message::Message>>`, but its trait bounds were not satisfied
  --> ezsp-fwupd/src/launch_bootloader.rs:30:14
   |
30 |         uart.launch_standalone_bootloader(MODE)
   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called due to unsatisfied trait bounds
   |
  ::: /home/neumann/RustroverProjects/ezsp/src/uart.rs:40:1
   |
40 | pub struct Uart<T> {
   | ------------------ doesn't satisfy `_: Bootloader` or `_: Transport`
   |
   = note: the following trait bounds were not satisfied:
           `Uart<tokio::sync::mpsc::Sender<ashv2::actor::message::Message>>: Transport`
           which is required by `Uart<tokio::sync::mpsc::Sender<ashv2::actor::message::Message>>: ezsp::Bootloader`

error[E0282]: type annotations needed
  --> ezsp-fwupd/src/launch_bootloader.rs:30:9
   |
30 | /         uart.launch_standalone_bootloader(MODE)
31 | |             .await
   | |__________________^ cannot infer type

Some errors have detailed explanations: E0282, E0599.
For more information about an error, try `rustc --explain E0282`.
error: could not compile `ezsp-fwupd` (lib) due to 2 previous errors

However, it appears to satisfy the needed trait bounds:

use ashv2::{Actor, DefaultProxy, Proxy, TryCloneNative};
use ezsp::Bootloader;
use ezsp::uart::Uart;
use log::{debug, error};
use serialport::SerialPort;
use tokio::sync::mpsc::channel;

use crate::discard_callbacks;

const MODE: u8 = 0x00;

/// Launch a standalone bootloader on the Zigbee NIC's UART.
pub trait LaunchBootloader {
    /// Launch a standalone bootloader on the Zigbee NIC's UART.
    fn launch_bootloader(self) -> impl Future<Output = std::io::Result<()>>;
}

impl<T> LaunchBootloader for T
where
    T: SerialPort + TryCloneNative + Send + Sync + 'static,
{
    async fn launch_bootloader(self) -> std::io::Result<()> {
        let (response_tx, response_rx) = channel(8);
        let (actor, proxy) = Actor::new(self, response_tx, 8)?;
        let (tx_handle, rx_handle) = actor.spawn();
        let (callbacks_tx, callbacks_rx) = channel(8);
        discard_callbacks(callbacks_rx);
        let mut uart: Uart<DefaultProxy> = Uart::new(proxy, response_rx, callbacks_tx, 8, 8);
        debug!("Launching standalone bootloader...");
        test_uart(uart);
        /*
        uart.launch_standalone_bootloader(MODE)
            .await
            .unwrap_or_else(|error| {
                error!("Failed to launch standalone bootloader: {error}");
            });

         */
        Ok(())
    }
}

fn test_uart<T>(uart: Uart<T>)
where
    T: Proxy + Send + Sync,
{
    assert!(true);
}

Resulting in:

  Compiling ezsp-fwupd v1.0.0 (/home/neumann/RustroverProjects/ezsp-fwupd/ezsp-fwupd)
warning: unused import: `ezsp::Bootloader`
 --> ezsp-fwupd/src/launch_bootloader.rs:2:5
  |
2 | use ezsp::Bootloader;
  |     ^^^^^^^^^^^^^^^^
  |
  = note: requested on the command line with `-W unused-imports`

warning: unused import: `error`
 --> ezsp-fwupd/src/launch_bootloader.rs:4:18
  |
4 | use log::{debug, error};
  |                  ^^^^^

warning: variable does not need to be mutable
  --> ezsp-fwupd/src/launch_bootloader.rs:28:13
   |
28 |         let mut uart: Uart<DefaultProxy> = Uart::new(proxy, response_rx, callbacks_tx, 8, 8);
   |             ----^^^^
   |             |
   |             help: remove this `mut`
   |
   = note: `#[warn(unused_mut)]` (part of `#[warn(unused)]`) on by default

warning: unused variable: `tx_handle`
  --> ezsp-fwupd/src/launch_bootloader.rs:25:14
   |
25 |         let (tx_handle, rx_handle) = actor.spawn();
   |              ^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_tx_handle`
   |
   = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default

warning: unused variable: `rx_handle`
  --> ezsp-fwupd/src/launch_bootloader.rs:25:25
   |
25 |         let (tx_handle, rx_handle) = actor.spawn();
   |                         ^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_rx_handle`

warning: unused variable: `uart`
  --> ezsp-fwupd/src/launch_bootloader.rs:43:17
   |
43 | fn test_uart<T>(uart: Uart<T>)
   |                 ^^^^ help: if this is intentional, prefix it with an underscore: `_uart`

warning: constant `MODE` is never used
  --> ezsp-fwupd/src/launch_bootloader.rs:10:7
   |
10 | const MODE: u8 = 0x00;
   |       ^^^^
   |
   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default

warning: `ezsp-fwupd` (lib) generated 7 warnings (run `cargo fix --lib -p ezsp-fwupd` to apply 6 suggestions)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.19s
~/RustroverProjects/ezsp-fwupd>         

In ezsp I have:

impl<T> Transport for Uart<T>
where
    T: Proxy + Send + Sync,
{
    ...
}

and

impl<T> Bootloader for T
where
    T: Transport,
{
    ...

    async fn launch_standalone_bootloader(&mut self, mode: u8) -> Result<(), Error> {
        self.communicate::<_, launch_standalone_bootloader::Response>(
            launch_standalone_bootloader::Command::new(mode),
        )
        .await?
        .try_into()
    }

    ...
}

I'll continue trying to get some MRE to work in case you need it, but maybe somebody can already see what I am not seeing here...

3 posts - 2 participants

Read full topic

🏷️ Rust_feed