rust-lang / rust-lang/rust-clippy
lint against float -> int casting
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 13.5k
- Forks
- 2.2k
- Avg merge
- 2d 10h
- Merged PRs (30d)
- 32
Description
What it does
Using the as keyword to cast between numeric types is hazardous, and is already covered by cast_sign_loss, cast_possible_truncation, and cast_possible_wrap.
Casting between integer types, though it may not be wise, at least has easy to remember semantics: when casting to a smaller type, it truncates, and when casting between signed/unsigned, it reinterprets the bits (possibly leading to under/overflow).
(reference)
Casting from floating point to integer has different behavior, comes with additional hazards, and needs extra weird semantics to cover special cases:
- NaNs are converted to 0.
- Out-of-range inputs (including +/- infinity) are saturated to the destination type's min/max values.
- Fractional numbers are rounded toward zero.
This produces some surprising results:
-1.0 as u32is0f32::NAN as i32is01e20 as u32is4294967295. (value is shrunk by 10 orders of magnitude)
This leaves me wondering if there should be a clippy lint that only targets as casting from floating-point to integer.
Advantage
This might be helpful for codebases where integer->integer casts are just too common to warn against.
Drawbacks
Arguments against such a lint include:
- All cases are already covered by the
cast_sign_lossandcast_possible_truncationlints, which also catch integer casts that may fail. Maybe it's silly to treat floating point inputs as special. - There isn't one obvious fix to suggest. The standard library doesn't offer fallible conversions for NaN and out-of-range inputs. There are crates that can help:
num_traits::NumCasthas fallible conversions;conv2has fallible conversions plus saturating, wrapping, rounding modes, etc.
Example
let x = some_float as u32;
Could be written as:
use conv2::ConvUtil;
let x = some_float.approx_as::<u32>().expect("input out of range");
or
use num_traits::NumCast;
let x: u32 = NumCast::from(x).expect("input out of range");
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by comparing the proposed lint with cast_sign_loss, cast_possible_truncation, and cast_possible_wrap, then review the linked Rust numeric-cast reference. Determine whether float-to-integer casts need distinct treatment and what behavior should be covered; done means the scope and rationale are resolved before implementation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100