Skip to content

[ty] Check shifts of Literal ints#18329

Closed
brandtbucher wants to merge 3 commits intoastral-sh:mainfrom
brandtbucher:shifts
Closed

[ty] Check shifts of Literal ints#18329
brandtbucher wants to merge 3 commits intoastral-sh:mainfrom
brandtbucher:shifts

Conversation

@brandtbucher
Copy link
Contributor

Fixes astral-sh/ty#517.

I took the liberty of adding a new negative-shift diagnostic for cases when we detect shifting by a negative RHS, which is a ValueError at runtime. This reuses some machinery that's already used to detect division by Literal[0] (division-by-zero), which felt sort of natural. I'm okay with refactoring or removing it, though... I was mostly just curious how new rules are added and used under-the-hood.

@brandtbucher brandtbucher changed the title Check shifts of literals ints [ty] Check shifts of Literal ints May 27, 2025
@brandtbucher
Copy link
Contributor Author

That was neat: mypy_primer failed because handling Literal shifts shook out an unrelated bug where negating Literal[-9223372036854775808] (i64::MIN) would panic due to overflow. I've fixed that in this PR as well, and added a regression test.

@github-actions
Copy link
Contributor

mypy_primer results

No ecosystem changes detected ✅

@brandtbucher
Copy link
Contributor Author

Yay Rust.

@brandtbucher
Copy link
Contributor Author

Just realized that this doesn't correctly handle the cases where we shift a 1 into the sign bit (like 1 << 63). I'll fix that tomorrow.

@MichaReiser MichaReiser marked this pull request as draft May 27, 2025 05:58
Copy link
Member

@AlexWaygood AlexWaygood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you also add some tests with boolean literals? E.g. True << 42, 56 >> False and True << True. Your branch gives the right answer for them, but it's good to explicitly test them, I think.

(They're covered by this fallback branch here:

(Type::BooleanLiteral(bool_value), right, op) => self.infer_binary_expression_type(
node,
emitted_division_by_zero_diagnostic,
Type::IntLiteral(i64::from(bool_value)),
right,
op,
),
(left, Type::BooleanLiteral(bool_value), op) => self.infer_binary_expression_type(
node,
emitted_division_by_zero_diagnostic,
left,
Type::IntLiteral(i64::from(bool_value)),
op,
),
)

/// 42 >> -1
/// 42 << -1
/// ```
pub(crate) static NEGATIVE_SHIFT = {
Copy link
Member

@AlexWaygood AlexWaygood May 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it's worth this being a separate lint to DIVISION_BY_ZERO, or if it might be better to group them both under a LITERAL_MATH_ERROR lint (which, like DIVISION_BY_ZERO, should probably be disabled by default for now):

  • They're conceptually pretty similar in the kind of error they detect
  • I can't really think of a reason why a user would want to suppress one (either on a per-line, per-file or per-project basis) but not the other
  • I think they both suffer from the same drawbacks that @carljm noted in the PR description for [ty] disable division-by-zero by default #18220 (comment)

Renaming the existing DIVISION_BY_ZERO lint might be a fair amount of busywork, though, so it's okay if you're not up to that! I think one of us could reasonably take on merging the two lints as a followup task. If you do keep this as a separate lint, though, I think it should probably be disabled by default, similar to DIVISION_BY_ZERO. (See #18220 for what the necessary changes there would look like!)

@MichaReiser
Copy link
Member

Thanks for your contribution. I'll close this as it seems to have gone stale. Anyone interested in picking this up. Feel free to open a new PR which addresses the feedback.

AlexWaygood added a commit that referenced this pull request Feb 16, 2026
…#23301)

## Summary

Fixes astral-sh/ty#517.

This PR revives #18329 /
#19281, but without the
controversial bit of those PRs (the new diagnostic). Rather than adding
a new diagnostic if an integer is left-shifted or right-shifted by a
negative number, we just ignore that and infer `int`. We can always add
a new diagnostic later, if we find consensus on it.

Along the way, Claude also discovered that
`reveal_type(-(-9223372036854775807 - 1))` currently reveals
`Literal[-9223372036854775808]` on `main`, which is... not correct. So
this PR fixes that too.

### Test Coverage

mdtests

Co-authored-by: Brandt Bucher <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add literal math support for shift operators

3 participants