Why is the Rhs of bitshift operations not forced to be unsigned/u8?

Hello,

I am a beginner in Rust and currently implement my own fixed-point arithemtic.
While implementing bitshift operations I noticed something that bugs me.

let a:i32 = 100;
let b = 3;
let c:i32 = a << b;

Why does b have to be i32 as well?
It makes no sense in my head that you can bitshift with a potentially negative value (I come form a C-like language). I would have thought that Rust tries to force me to use an unsigned type here to enforce more code safety. Maybe even just u8 as there is no primitive type that makes sense to apply bitshifts of more than 63.

Thanks for the upcoming replies. :slight_smile:

b doesn't have to be i32.
In fact any integer type should work:

Playground

fn main() {
    let a: i32 = 100;
    let b = 3u8;
    let c: i32 = a << b;
}

The implementation defines it for all combinations of integers: https://doc.rust-lang.org/src/core/ops/bit.rs.html#395-430

It doesn't have to be. Shl is implemented for every combination of integer lhs and rhs. The type checker just defaults the rhs type to the lhs type. If you explicitly specify a type for b, then it will use that type just fine.

https://doc.rust-lang.org/stable/std/ops/trait.Shl.html

Note that because this trait is implemented for all integer types with multiple right-hand-side types, Rust's type checker has special handling for _ << _ , setting the result type for integer operations to the type of the left-hand-side operand.

In C shifting by an amount that is equal or greater than the bitsize of the lhs is UB. In Rust this can't be true. Thus in debug mode you get a panic and in release mode the rhs is masked such that the UB can't happen.

We have u128 and i128.

Even limiting to u8 would not be enough, as you could still have values bigger than the maximum sensible shift amount.

Thanks for the replies!

If I enforce b to be u8 for example, I get an error in the third line:

let a: i32 = 100;
let b: u8 = 3;
let c: i32 = a << b;

mismatched types [E0308]: expected i32, found u8

Why is this error raised when I should be allowed to apply u8 as Rhs?
I work with IntelliJ IDEA.

It works fine on the playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=243520eeade377fb77fe46861b256c47

I just saw that, it is weird my IDE does not allow that.

IDE cannot throws compile error. Maybe it's the feature recently (kind of) added and you have an outdated toolchain installed?

The Intellij Rust plugin does have that error: https://github.com/intellij-rust/intellij-rust/blob/5936e3e205ceebfaaae8633e0ae1438546c3d4f4/src/main/kotlin/org/rust/lang/utils/RsDiagnostic.kt#L75

It is supported all the way back to Rust 1.0.0.

2 Likes

Note that the Shl trait, std::ops::Shl, can be applied to more than machine-level integers. The second example in the documentation of the trait spins a vector leftward by a given amount. That vector could have up to isize::MAX entries, a value much larger than u8::MAX.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.