Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is std::ops::Shl::shl not equal to <<?

Tags:

types

rust

In mutagen, I use specialization to mutate binary operations where possible. Basically, I replace a + b with ::mutagen::AddSub::add(a, b, mutation_count) Alas, it fails in the presence of shift operations, because type inference fails.

I've reduced the problem to a very simple test case:

use std::ops::Shl;

fn main() {
    println!("{}", 1u32.shl(2) * 3);
}

This fails with error[E0277]: cannot multiply i32 to u32. This appears to happen because std::ops::Shl is implemented for all sorts of integers, and while those impls always return the self type (but not Self, as I see from the source), typeck may not see through them, and coming up empty, defaulting to i32. If you replace the 1u32.shl(2) with (1u32 << 2), it works.

So forwarding std::ops::Shl/Shr won't work either using a custom trait (as in pub trait AddSub) or using a wrapper type for the left-hand side of the operation. In both cases, the type inference fails to see the equality of Self and Self::Output for integer shifts, despite knowing Self.

Is this a bug? Is there a workaround? What causes it?

like image 340
llogiq Avatar asked Apr 09 '18 10:04

llogiq


1 Answers

This is not a bug. The reason for this is some special binary operations handling for non (or semi-)inferred types in typeck.

A workaround is to fix the return type of the expression by using an if-expression where one branch is the original binary operation and the other is the mutated operation, e.g.

(if ::mutagen::now(42) {
     ::mutagen::ShlShr::shl(left, right)
 } else {
     left << right
 })
like image 116
llogiq Avatar answered Oct 10 '22 00:10

llogiq