Ran into something unusual while fighting the borrow checker. This little snippet of code type-checks but in essence its a recursive call (i.e. a call to as_ref() recurs forever) that ends in a stack overflow.
Which does type-check, but overflows the stack because the function keeps calling itself forever. In your case as_ref() calls itself forever.
Did you mean to expose the usize field as bytes? Rust is going to get as_ne_bytes for it someday. For now you will need to do some pointer casting and std::slice::from_raw_parts.
I actually stumbled upon this while writing some generic code (a bit lengthy so I'll summarize). My generic type needed the AsRef<[u8]> trait bound and State - in this example is one of the possible (generic) types which is required to satisfy the - AsRef<[u8]> bound
So, I just did this and it worked. I only need the trait-bound for my other possible (generic) types such as a [u8; N]
It's almost never a compiler bug. Of course a function that only calls itself typechecks: its arguments and return type are the same as… well, itself!
In general, there could be an argument in favor of detecting infinite recursion, infinite loops, etc., however:
it's not possible to detect arbitrary runtime behavior, divergence included, in the general case.
Infinite loops and/or infinite recursion can be intentional (e.g. for a background process that is not supposed to stop, like a web server).
However the compiler tries to detect simple cases (like op's) anyway and warns about them. This is useful when for example when you're delegating the implementation of a trait for &T to that of T but you mess up and end up calling the method for &T, leading to infinite recurison.
You can also use loop {} to "trick" the type-checker although that's the intended behavior.
A type signature on a function promises that, if the function converges, then the result will be of the specified type. It does not promise that the function actually converges - and in general that property (provably) can’t be checked.
The return value of as_ref is guaranteed to be &[u8] if as_ref converges, and that’s enough to satisfy the requirement that all return values out of as_ref must be &[u8], so the function body is valid. The function happens not to converge, but that’s allowed for any function.
One consequence of this is that expressions like panic!(...), which are guaranteed not to converge, satisfy any type.