Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

op! macro does not support generics #207

Open
seftontycho opened this issue Mar 26, 2024 · 8 comments
Open

op! macro does not support generics #207

seftontycho opened this issue Mar 26, 2024 · 8 comments

Comments

@seftontycho
Copy link

I am trying to implement the following trait as follows:

// Shift left is False, shift right is True
pub trait NormaliseInner<U: Unsigned, Hint: Bit> {
    type Output;
}

impl<S, E, M, U> NormaliseInner<U, True> for F32<S, E, M>
where
    S: Bit,
    E: Unsigned + Add<U>,
    M: Unsigned + Shr<U>,
    U: Unsigned,
    op!(E + U): Unsigned,
    op!(M >> U): Unsigned,
{
    type Output = op!(F32<S, E, M> >> U);
}

I have implemented Shr<U: Unsigned> for F32<S, E, M>.

impl<S, E, M, U> Shr<U> for F32<S, E, M>
where
    S: Bit,
    E: Unsigned + Add<U>,
    M: Unsigned + Shr<U>,
    U: Unsigned,
    op!(E + U): Unsigned,
    op!(M >> U): Unsigned,
{
    type Output = F32<S, op!(E + U), op!(M >> U)>;

    fn shr(self, _rhs: U) -> Output {
        F32::new()
    }
}

However I am getting an error:

   --> src/addition.rs:111:19
    |
111 |     type Output = op!(F32<S, E, M> >> U);
    |                   ^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`typequake`)
    = note: this error originates in the macro `__op_internal__` which comes from the expansion of the macro `op` (in Nightly builds, run with -Z macro-backtrace for more info)

error: could not compile `typequake` (lib) due to 1 previous error

What am I doing wrong?
And how would you reccomend debugging such issues in the future?

@paholg
Copy link
Owner

paholg commented Mar 26, 2024

For debugging macros in general, I have found cargo expand to be very useful.

In this particular case, the macro expansion is simple enough that it can be done by hand:

type Output = <F32<S, E, M> as Shr<U>>::Output;

Your actual issue is that your Shr implemention is recursive with no base-case, so it will infinitely recurse. If you look at how arithmetic is implemented in typenum, it's also recursive, but there's always a base case.

For example, in peano (which is like a simpler typenum that uses counting instead of binary for integer representation), here is how adding positive numbers is implemented: https://github.com/paholg/peano/blob/f8d288f133a90fde271fcc8164d74158cd7e9f70/src/lib.rs#L142-L152

The second impl block is recursive, counting down one of the operands and up the other, whereas the first impl block acts as the base-case, coming into play once the left operand hits 0.

In typenum, zero is representing by UTerm and non-zero numbers are respresented by UInt<U, B> where U is some unsigned number, and B is a bit.

I suspect you can make your implementation work by having one impl where M is replaced with UInt<M, B>, and other where M is replaced with UTerm, since M tends toward zero. Though you'd still run into trouble if U is zero, maybe give it a NonZero bound.


https://github.com/dtolnay/cargo-expand

@seftontycho
Copy link
Author

seftontycho commented Mar 26, 2024

I tried cargo expand but it gave me the same error.

Could you explain how my Shr implementation is recursive?
As E, M, and U are all Unsigned, actually they are all just UInt, I would have thought typenum's implementations of Shr would handle this already?

@paholg
Copy link
Owner

paholg commented Mar 26, 2024

Oh sorry, I misread. You're right, I don't think it is recursive. I'll try to look into this if I have time.

@seftontycho
Copy link
Author

Thank you!

Essentially I am trying to implement F32s following IEEE 754 and I am calling Normalise after performing arithmetic operations to ensure that the mantissa is in the required range.

@paholg
Copy link
Owner

paholg commented Mar 26, 2024

Oh huh, I also misunderstood the error. It is a recursion in the macro, not the type resolution; this error shows up even if F32 is undefined!

This is definitely a typenum bug. In the meantime, you can manually expand the code as I did.

@paholg
Copy link
Owner

paholg commented Mar 26, 2024

Aha, it's the way I wrote the macro. It expects all operands to be idents, so the generics don't work. I imagine this is either a very easy fix or a very hard one :).

@seftontycho
Copy link
Author

I only need to change to explicit version for uses of op! with generics then?
If so that's totally fine.

I will take a look at the macro later also.
Thank you for the very quick response.

My dream for (totally useless), compile time fast inverse square root is alive still.

@paholg
Copy link
Owner

paholg commented Mar 26, 2024

Haha, that sounds great! Good luck with it!

@paholg paholg changed the title How to debug recursion errors in op! op! macro does not support generics Mar 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants