From 438ef334d3e71ef0ac70927c799fb159d8f25267 Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Fri, 21 Nov 2025 14:02:12 -0500 Subject: [PATCH] [ty] Fix subtraction overflow bug PR #21549 introduced a subtle overflow bug that seemed impossible, but can empirically happen. This PR fixes it by saturating to zero. I did try to write a regression test for this, but couldn't manage it. Instead, I'll attach before-and-after screen recordings. --- crates/ruff_text_size/src/size.rs | 19 +++++++++++++++++++ crates/ty_ide/src/completion.rs | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/crates/ruff_text_size/src/size.rs b/crates/ruff_text_size/src/size.rs index e4e45be7a8..aa4a8571e3 100644 --- a/crates/ruff_text_size/src/size.rs +++ b/crates/ruff_text_size/src/size.rs @@ -106,6 +106,25 @@ impl TextSize { pub fn checked_sub(self, rhs: TextSize) -> Option { self.raw.checked_sub(rhs.raw).map(|raw| TextSize { raw }) } + + /// Saturating addition. Returns maximum `TextSize` if overflow occurred. + #[inline] + #[must_use] + pub fn saturating_add(self, rhs: TextSize) -> TextSize { + TextSize { + raw: self.raw.saturating_add(rhs.raw), + } + } + + /// Saturating subtraction. Returns minimum `TextSize` if overflow + /// occurred. + #[inline] + #[must_use] + pub fn saturating_sub(self, rhs: TextSize) -> TextSize { + TextSize { + raw: self.raw.saturating_sub(rhs.raw), + } + } } impl From for TextSize { diff --git a/crates/ty_ide/src/completion.rs b/crates/ty_ide/src/completion.rs index cb82d82f9e..a25f042866 100644 --- a/crates/ty_ide/src/completion.rs +++ b/crates/ty_ide/src/completion.rs @@ -1341,7 +1341,7 @@ fn is_in_definition_place( /// E.g. naming a parameter, type parameter, or `for` ). fn is_in_variable_binding(parsed: &ParsedModuleRef, offset: TextSize, typed: Option<&str>) -> bool { let range = if let Some(typed) = typed { - let start = offset - typed.text_len(); + let start = offset.saturating_sub(typed.text_len()); TextRange::new(start, offset) } else { TextRange::empty(offset)