Skip to content

Instantly share code, notes, and snippets.

@nikomatsakis
Last active August 29, 2015 14:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nikomatsakis/11179747 to your computer and use it in GitHub Desktop.
Save nikomatsakis/11179747 to your computer and use it in GitHub Desktop.

Results of Integer fallback investigation

I made the following changes:

  • Require array repeat counts to be uints ([expr, ..count])
  • Make << and >> operators require uint for the shift count when applied to integral types
    • current behavior is: accept any integral type at all
  • Improve type inferencer so that things like 3 as u8 or 0 as *T get inferred
    • Basically track downward the type that an expression is being cast to
    • A bit more subtle than existing inference mechanism
  • Added warning for int fallback

Code at https://github.com/nikomatsakis/rust/tree/remove-int-fallback

After those changes, the warnings that remain fall into 4 categories:

  • Pointless casts (2)
  • Enum discriminants (29)
  • Range (3)
  • Counters (14)
  • ISAAC (24, see below)

Pointless casts (2)

Occasionally, people add casts that aren't needed. For example:

-    fn size(&self) -> int { (1 << self.log_size) as int }
+    fn size(&self) -> int { 1 << self.log_size }

These generate a lack of constraints, but I'd say the code reads nicer the new way anyhow.

Enum discriminants (20)

For something like

enum Color { Red = 0, Green = 1, Blue = 2 }

we generate no particular constraint on the types of those constants, then default to int. I propose we just say that these constants must be typed as int (i.e., writing Red = 0_i64 would be an error). Or special case this to retain current behavior just in this instance (enum discriminants are so weird).

Range (3)

Some code does:

for _ in range(0, 10) { ... }

Naturally this is unconstrained. In such cases, we would have to either:

  1. add another iterator (like times) that requires a uint and encourage people to use that
  2. change the code to range(0u, 10)

Counters (14)

There are bits of code that do:

let mut c = 0;
loop {
    ...;
    c += 1;
}
println!("{}", c);

The counter c here is unconstrained and we pick int. In most cases I examined, this seems...slightly wrong, in that uint would have been a better choice.

ISAAC

ISAAC does some odd stuff using macros that I can't quite categorize. It winds up with a lot of duplicate error reports because the same macro blats the same code 4 or 5 times, with distinct constants. Example:

                rngstep!(i + 0, 13);
                rngstep!(i + 1, -6);
                rngstep!(i + 2, 2);
                rngstep!(i + 3, -16);

where rngstep! is:

        macro_rules! rngstep(
            ($j:expr, $shift:expr) => {{
                let base = $j;
                let mix = if $shift < 0 {
                    a >> -$shift as uint
                } else {
                    a << $shift as uint
                };

                let x = self.mem[base  + mr_offset];
                a = (a ^ mix) + self.mem[base + m2_offset];
                let y = ind!(x) + a + b;
                self.mem[base + mr_offset] = y;

                b = ind!(y >> RAND_SIZE_LEN) + x;
                self.rsl[base + mr_offset] = b;
            }}
        );

Note that $shift < 0 expands to something like 17 < 0 or whatever, which leaves the type of 17 and 0 unconstrained.

@emberian
Copy link

As for range I think it's fine to have to write 0u or whatever. I usually do anyway (because I'm not working with ints) and it's not that burdensome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment