CensoredUsername/dynasm-rs

Mismatched type error when writing generic code

mkeeter opened this issue · 2 comments

I recently tried to make my functions more generic, taking a <D: DynasmApi + DynasmLabelApi> instead of a VecAssembler. To my surprise, this doesn't compile:

use dynasmrt::{dynasm, DynasmApi, DynasmLabelApi};

pub fn loopy<D: DynasmApi + DynasmLabelApi>(ops: &mut D) {
    dynasm!(ops
        ; ->Loop:
        ; b >Loop
    );
}
    Checking dynasm-test v0.1.0 (/Users/mkeeter/code/dynasm-test)
error[E0308]: mismatched types
   --> src/lib.rs:6:14
    |
4   | /     dynasm!(ops
5   | |         ; ->Loop:
6   | |         ; b >Loop // we're done!
    | |              ^^^^ expected associated type, found tuple
7   | |     );
    | |_____- arguments to this function are incorrect
    |
    = note: expected associated type `<<D as DynasmLabelApi>::Relocation as Relocation>::Encoding`
                         found tuple `(u8,)`
    = help: consider constraining the associated type `<<D as DynasmLabelApi>::Relocation as Relocation>::Encoding` to `(u8,)` or calling a method that returns `<<D as DynasmLabelApi>::Relocation as Relocation>::Encoding`
    = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
note: associated function defined here
   --> /Users/mkeeter/.cargo/registry/src/github.com-1ecc6299db9ec823/dynasmrt-2.0.0/src/lib.rs:250:8
    |
250 |     fn forward_reloc( &mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: <Self::Relocation as R...
    |        ^^^^^^^^^^^^^

It expands to

#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
use dynasmrt::{dynasm, DynasmApi, DynasmLabelApi};
pub fn loopy<D: DynasmApi + DynasmLabelApi>(ops: &mut D) -> usize {
    {
        ops.global_label("Loop");
        ops.extend(b"\x00\x00\x00\x14");
        ops.forward_reloc("Loop", 0isize, 4u8, 4u8, (0u8,));
    };
}

It seems like codegen is happy to generate kind: <Self::Relocation as Relocation>::Encoding as a (u8,), but the trait bounds of DynasmApi + DynasmLabelApi don't actually enforce that type, so we can't write this generic code.

I could add a further constraint <<D as DynasmLabelApi>::Relocation as Relocation>::Encoding: (u8,), but that's awfully wordy!

It likely needs some kind of bound like where D::Relocation=X64Relocation (or where <D as DynasmLabelApi>::Relocation=X64Relocation).

After some fighting with the compiler, the correct signature is

pub fn loopy<D: DynasmApi + DynasmLabelApi<Relocation = dynasmrt::aarch64::Aarch64Relocation>>(
    ops: &mut D,
) {

Thanks!