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

Exp and Shleft with constant left side fail. #75

Open
WaDelma opened this issue Dec 6, 2016 · 13 comments
Open

Exp and Shleft with constant left side fail. #75

WaDelma opened this issue Dec 6, 2016 · 13 comments
Labels
bug likely-rust-bug Likely a compiler bug

Comments

@WaDelma
Copy link

WaDelma commented Dec 6, 2016

I am trying to calculate 2.pow(n) for generic array size and failing misserably.

If I do Exp<U2, N> or Shleft<U1, N>, compilation fails from overflowing while trying figure out Sized bound.

I have tried all kinds of bounds for N, but without success. Is this just not possible or am I missing some crucial thing?

@paholg
Copy link
Owner

paholg commented Dec 8, 2016

This should work fine ... I'll look into it.

Any chance you could post a longer snippet so I can see exactly what you're doing?

@paholg
Copy link
Owner

paholg commented Dec 9, 2016

I have verified that this

    println!("{}", <Exp<U2, U10> as Unsigned>::to_u32());

works fine, so I'll definitely need to see how you're using it to be able to help.

@WaDelma
Copy link
Author

WaDelma commented Dec 10, 2016

I am trying to do something like this:

struct Struct<N: Unsigned> {
     data: GenericArray<f64, Exp<U2, N>>
}

but the same problem happens with functions:

fn function<N: Unsigned>() -> u64 {
    <Shleft<U1, N> as Unsigned>::to_u64()
}

Error it gives: http://pastebin.com/UpsHSWSV
and if you increase the recursion limit it just gives more of the same stuff, so there is infinite recursion there.

@paholg
Copy link
Owner

paholg commented Dec 11, 2016

Ah, this is the case of a poor compiler message.

What is happening is that you can do what you want, but the compiler doesn't know that, and it's freaking out instead of informing you.

While U2 can be raised to any Unsigned power N, and the result will be Unsigned (which also means it will be ArrayLength<f64>, as required by GenericArray), we have to provide annotations to that effect:

struct Struct<N: Unsigned> where U2: Pow<N>, Exp<U2, N>: ArrayLength<f64> {
     data: GenericArray<f64, Exp<U2, N>>
}

or

fn function<N: Unsigned>() -> u64 where U1: Shl<N>, Shleft<U1, N>: Unsigned {
    <Shleft<U1, N> as Unsigned>::to_u64()
}

If you were to change exponentiation to, say, multiplication, then you get a much more sane error message:

error[E0277]: the trait bound `typenum::UInt<typenum::UInt<typenum::UTerm, typenum::B1>, typenum::B0>: std::ops::Mul<N>` is not satisfied
  --> src/main.rs:10:6
   |
10 |      data: GenericArray<f64, Prod<U2, N>>,
   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `typenum::UInt<typenum::UInt<typenum::UTerm, typenum::B1>, typenum::B0>: std::ops::Mul<N>` not satisfied
   |
   = help: consider adding a `where typenum::UInt<typenum::UInt<typenum::UTerm, typenum::B1>, typenum::B0>: std::ops::Mul<N>` bound

error: aborting due to previous error

@WaDelma
Copy link
Author

WaDelma commented Dec 12, 2016

Ahh... That was it. I was trying all sorts of bounds, but didn't realise you could give bounds like that to concrete types.

After getting that fixed I tried to create constructor for my type like this:

impl<N: Unsigned> Struct<N>
    where U2: Pow<N>,
          Exp<U2, N>: ArrayLength<f64>,
{
    fn from_slice(data: &[f64]) -> Struct<N> {
        Struct {
            data: GenericArray::from_slice(data)
        }
    }
}

and encountered the same problem...

Is there any plans for creating some kind of tutorial for resolving these kinds of problems? I would think that encountering these without any help would hugely discoure people from using typenum.

And is there issue in rust-lang/rust to make those errors better?

@paholg
Copy link
Owner

paholg commented Dec 12, 2016

Is there any plans for creating some kind of tutorial for resolving these kinds of problems?

I haven't had any, but that's a great idea. I'm just not sure when I'd be able to get around to it.

And is there issue in rust-lang/rust to make those errors better?

None that I'm aware of. I've been wanting to submit an issue (although I haven't searched yet so one may exist), but I'd want to spend some time and get a minimal example first. You are, of course, welcome to submit one---if you do, I'd love a link to it here.

As for you constructor issue, I'm not really sure what's going on, but it's almost certainly related to the error messages. I've tried to play with it a bit, but didn't get it to work. I may try more later.

Typenum pushes Rust's type system to its limits, and sometimes it gets grumpy about it. Often, I've managed to solve similar issues with trivial-seeming refactoring. Basically a lot of "maybe if I do it this way it'll work", and, at some point, it finally does.

You may be interested in #61, as @mkeeter seems to be doing something similar, and might have solved the constructor issue.

@WaDelma
Copy link
Author

WaDelma commented Dec 12, 2016

Actually just trying to create the struct fails:
let t: Struct<U5> = Struct{data: GenericArray::<f64, Exp<U2, U5>>::from_slice(t)};

@WaDelma
Copy link
Author

WaDelma commented Dec 13, 2016

Welp... I tried to reduce the code and got to this point:

fn wut(t: &[f64])
    where U1: Pow<U1>,
          <UInt<UTerm, B1> as Pow<UInt<UTerm, B1>>>::Output: ArrayLength<f64>
{
    let _ = GenericArray::<f64, Exp<U1, U1>>::from_slice(t);
}

which fails with:

error[E0277]: the trait bound `<typenum::UInt<typenum::UTerm, typenum::B1> as typenum::Pow<typenum::UInt<typenum::UTerm, typenum::B1>>>::Output: generic_array::ArrayLength<f64>` is not satisfied
  --> src\lib.rs:70:13
   |
70 |     let _ = GenericArray::<f64, Exp<U1, U1>>::from_slice(t);
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `<typenum::UInt<typenum::UTerm, typenum::B1> as typenum::Pow<typenum::UInt<typenum::UTerm, typenum::B1>>>::Output: generic_array::ArrayLength<f64>` not satisfied
   |
   = help: consider adding a `where <typenum::UInt<typenum::UTerm, typenum::B1> as typenum::Pow<typenum::UInt<typenum::UTerm, typenum::B1>>>::Output: generic_array::ArrayLength<f64>` bound
   = note: required by `<generic_array::GenericArray<T, N>>::from_slice`

Which makes literally no sense to me....

Edit(1):
Wait what:
let _ = GenericArray::<f64, <UInt<UTerm, B1> as Pow<UInt<UTerm, B1>>>::Output>::from_slice(t);
works

Edit(2): I reduced the original reduction from:

fn wut(t: &[f64])
    where U1: Pow<U1>,
          Exp<U1, U1>: ArrayLength<f64>,
{
    let _ = GenericArray::<f64, Exp<U1, U1>>::from_slice(t);
}

just before submitting it

Edit(3): For function that creates GenericArray changing Exp<U2, N> to <U2 as Pow<N>>::Output works. For structs and constructors it doesn't.

@WaDelma
Copy link
Author

WaDelma commented Jan 13, 2017

I experimented with this a little more.

struct Struct<T>(T);

impl Struct<()> {
    fn from_slice<N>(data: &[f64]) -> Struct<N>
        where U2: Pow<N>,
                   <U2 as Pow<N>>::Output: ArrayLegth<f64>,
    {
        Struct(GenericArray::<f64, <U2 as Pow<N>>::Output>::from_slice(data))
    }
}

works for faking constructor, but for methods this doesn't work. And it's still bit strange as if you try to call it like Struct::<U5>::from_slice(s) it doesn't work.

If I move the bounds to the impl, it breaks.

@paholg
Copy link
Owner

paholg commented Mar 25, 2017

Some longstanding bugs have been fixed as of Rust 1.17.0 (the current beta), and at least some of your issues have been fixed.

Your function wut, at least, compiles now. I tried to get your last example to work, but Struct(GenericArray::<f64, <U2 as Pow<N>>::Output>::from_slice(data)) does not have type Struct<N>, so I'm not sure exactly what to do there.

Anyway, I'd invite you to revisit this using beta or nightly, and let me know if you're still having issues.

@WaDelma
Copy link
Author

WaDelma commented Mar 25, 2017

I got this working:

struct Test<N: Unsigned>(GenericArray<f64, <U2 as Pow<N>>::Output>)
    where U2: Pow<N>,
          <U2 as Pow<N>>::Output: ArrayLength<f64>;

fn from_slice<N: Unsigned>(data: &[f64]) -> Test<N>
    where U2: Pow<N>,
          <U2 as Pow<N>>::Output: ArrayLength<f64>,
{
    Test::<N>(GenericArray::<f64, <U2 as Pow<N>>::Output>::from_slice(data))
}

fn doit() {
    let test = from_slice::<U5>(&[
    0.,
    0., 0., 0., 0., 0.,
    0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
    0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
    0., 0., 0., 0., 0.,
    0.,
    ]);
}

but if I try to make that from_slice to be a method it fails with the usual E0275:

impl<N: Unsigned> Test<N>
    where U2: Pow<N>,
          <U2 as Pow<N>>::Output: ArrayLength<f64>,
{
    fn from_slice(data: &[f64]) -> Test<N> {
        Test::<N>(GenericArray::<f64, <U2 as Pow<N>>::Output>::from_slice(data))
    }
}

fn doit() {
    let test = Test::<U5>::from_slice(&[
    0.,
    0., 0., 0., 0., 0.,
    0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
    0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
    0., 0., 0., 0., 0.,
    0.,
    ]);
}

Atleast some progress :D

@paholg
Copy link
Owner

paholg commented Aug 13, 2018

I was curious and wanted to see if compiler improvements had fixed this.

For the record, it's still broken. Using

  • generic-array 0.11.1
  • typenum 1.10.0
  • rustc 1.30.0-nightly (73c78734b 2018-08-05) (also 1.28.0)

I still get this error. Full example, modified to work with new generic-array, for easier future testing:

extern crate generic_array;

use generic_array::typenum::*;
use generic_array::{ArrayLength, GenericArray};

struct Test<N: Unsigned>(GenericArray<f64, Exp<U2, N>>)
where
    U2: Pow<N>,
    Exp<U2, N>: ArrayLength<f64>;

impl<N: Unsigned> Test<N>
where
    U2: Pow<N>,
    <U2 as Pow<N>>::Output: ArrayLength<f64>,
{
    fn from_slice(data: &[f64]) -> Test<N> {
        Test::<N>(GenericArray::<f64, <U2 as Pow<N>>::Output>::clone_from_slice(data))
    }
}

fn main() {
    let test = Test::<U5>::from_slice(&[
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0.,
    ]);
}

@WaffleLapkin
Copy link
Contributor

Still broken on 1.45.0-nightly. Is it a rustc bug? Are there any issues about that in rustc repo?

@paholg paholg added bug likely-rust-bug Likely a compiler bug labels Mar 12, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug likely-rust-bug Likely a compiler bug
Projects
None yet
Development

No branches or pull requests

3 participants