I decided to think a bit more about my literal types idea, and ended up deciding it wasn't worth the additional complexity. Here's a summary of my thoughts, for the curious:
- Introduce
ilit
andflit
primitive types (bikeshedable names; see alsoi__
andf__
). These would be the types of unqualified numerical literals, which compiler errors currently refer to as{integer}
and{float}
, similar to how string literals type as&'static str
. - These types automatically coerce to as integer literals do today: either to the numeric type expected by inference, or
i32
/f64
, respectively, if no type is inferred. const
bindings may be declaredilit
andflit
. I imagine the following (imaginary) desugaring:
const MASK: ilit = 0b0101_1010;
let foo = MASK;
assert_eq!(size_of_val(&foo), 4);
// desugars to
macro_rules! MASK { () => {0b0101_1010} }
let foo = MASK!();
assert_eq!(size_of_val(&foo), 4);
- These types do not implement
Sized
, since they are only meant to live in compile-type constants, where their size would be determined at the callsite. The question remains if we would ban their pointer types, which we certainly do not want running around; they could also be made into a(byte_len, ptr)
fat pointer, but I really don't think this is a good idea. This is especially confusing forflit
s.
The sole purpose of such a pseudo-type would be to allow for constants that have the same inference behavior as literals, which can currently be approximated with macros, and which I am unsure is even a good solution to the original stated problem.
I like this! We ostensibly have things like m8
and friends in std::simd
(in the form of mask vectors, which mainly exist as part of simd
support). We could take this one step further: it might not be an awful idea to add "mask types" which can only be BitAnd
ed, BitOr
ed, and BitXor
ed with each other and unsigned integers, and have the extension/truncation behavior you expect. It would neatly solve the inference problem if integer literals are inferred as mask types only when all other integer types (including i32
) are not valid inference targets (or, more simply, require writting const MASK: m8 = 0b0101_0101m8;
).
All of this, except for the inference part, can be done in a library already.