Update Rust toolchain to 1.99 and MSRV to 1.97 (#29047)

## Summary

- Update the Rust toolchain to 1.99.0 and the MSRV to 1.97, following
our N-2 support policy.
- Address the new Clippy warnings and preserve our existing assertion
and formatting macro conventions.
- Update Hawk to 0.1.15 and run it with Rust 1.99.0.
This commit is contained in:
Charlie Marsh authored and GitHub committed 2026-10-01 12:20:10 -04:00
1 parent 317e0a3ab7
commit 41d30df6fd
8 files changed
+86 -85

No files matched your search

+3 -3
View File
@@ -25,7 +25,7 @@ env:
CARGO_PROFILE_DEV_OPT_LEVEL: 0
CARGO_TERM_COLOR: always
# renovate: datasource=github-releases depName=astral-sh/hawk
HAWK_VERSION: 0.1.13
HAWK_VERSION: 0.1.15
RUSTUP_MAX_RETRIES: 10
PACKAGE_NAME: ruff
PYTHON_VERSION: "3.14"
@@ -355,13 +355,13 @@ jobs:
cache-workspace-crates: "false"
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: "Install Rust toolchain"
run: rustup toolchain install 1.98.0
run: rustup toolchain install 1.99.0
- name: "Install Hawk"
run: |
curl --proto '=https' --tlsv1.2 -LsSf \
"https://github.com/astral-sh/hawk/releases/download/${HAWK_VERSION}/cargo-hawk-installer.sh" | sh
- name: "Hawk"
run: cargo +1.98.0 hawk check --target-dir target/hawk -D warnings
run: cargo +1.99.0 hawk check --target-dir target/hawk -D warnings
cargo-publish-dry-run:
name: "cargo publish dry-run"
+4 -1
View File
@@ -5,7 +5,7 @@ resolver = "2"
[workspace.package]
# Please update rustfmt.toml when bumping the Rust edition
edition = "2024"
rust-version = "1.96"
rust-version = "1.97"
homepage = "https://docs.astral.sh/ruff"
documentation = "https://docs.astral.sh/ruff"
repository = "https://github.com/astral-sh/ruff"
@@ -272,6 +272,7 @@ pedantic = { level = "warn", priority = -2 }
# Enabled at the crate level
disallowed_methods = "allow"
# Allowed pedantic lints
assert_is_empty = "allow"
char_lit_as_u8 = "allow"
collapsible_else_if = "allow"
collapsible_if = "allow"
@@ -282,6 +283,8 @@ missing_errors_doc = "allow"
missing_panics_doc = "allow"
module_name_repetitions = "allow"
must_use_candidate = "allow"
# Our formatting macros share names with std macros but use square brackets.
nonstandard_macro_braces = "allow"
similar_names = "allow"
single_match_else = "allow"
too_many_lines = "allow"
+75 -76
View File
@@ -430,96 +430,95 @@ pub fn check(args: CheckCommand, global_options: GlobalConfigArgs) -> Result<Exi
)?;
printer.write_continuously(&mut writer, &diagnostics, preview, prefer_rule_codes)?;
}
}
// Generate lint violations.
let diagnostics = if is_stdin {
commands::check_stdin::check_stdin(
cli.stdin_filename.map(fs::normalize_path).as_deref(),
&pyproject_config,
&config_arguments,
noqa.into(),
fix_mode,
)?
} else {
// Generate lint violations.
let diagnostics = if is_stdin {
commands::check_stdin::check_stdin(
cli.stdin_filename.map(fs::normalize_path).as_deref(),
&pyproject_config,
&config_arguments,
noqa.into(),
fix_mode,
)?
} else {
commands::check::check(
&files,
&pyproject_config,
&config_arguments,
cache.into(),
noqa.into(),
fix_mode,
unsafe_fixes,
)?
};
commands::check::check(
&files,
&pyproject_config,
&config_arguments,
cache.into(),
noqa.into(),
fix_mode,
unsafe_fixes,
)?
};
// Always try to print violations (though the printer itself may suppress output)
// If we're writing fixes via stdin, the transformed source code goes to the writer
// so send the summary to stderr instead
let mut summary_writer = if is_stdin && matches!(fix_mode, FixMode::Apply | FixMode::Diff) {
stderr_writer
} else {
writer
};
if cli.statistics {
printer.write_statistics(&diagnostics, &mut summary_writer)?;
} else {
printer.write_once(
&diagnostics,
&mut summary_writer,
preview,
prefer_rule_codes,
)?;
}
// Always try to print violations (though the printer itself may suppress output)
// If we're writing fixes via stdin, the transformed source code goes to the writer
// so send the summary to stderr instead
let mut summary_writer = if is_stdin && matches!(fix_mode, FixMode::Apply | FixMode::Diff) {
stderr_writer
} else {
writer
};
if cli.statistics {
printer.write_statistics(&diagnostics, &mut summary_writer)?;
} else {
printer.write_once(
&diagnostics,
&mut summary_writer,
preview,
prefer_rule_codes,
)?;
}
if !cli.exit_zero {
let max_severity = diagnostics
.inner
.iter()
.map(Diagnostic::severity)
.max()
.unwrap_or(Severity::Info);
if max_severity.is_fatal() {
// When a panic/fatal error is reported, prompt the user to open an issue on github.
// Diagnostics with severity `fatal` will be sorted to the bottom, and printing the
// message here instead of attaching it to the diagnostic ensures that we only print
// it once instead of repeating it for each diagnostic. Prints to stderr to prevent
// the message from being captured by tools parsing the normal output.
let message = "Panic during linting indicates a bug in Ruff. If you could open an issue at:
if !cli.exit_zero {
let max_severity = diagnostics
.inner
.iter()
.map(Diagnostic::severity)
.max()
.unwrap_or(Severity::Info);
if max_severity.is_fatal() {
// When a panic/fatal error is reported, prompt the user to open an issue on github.
// Diagnostics with severity `fatal` will be sorted to the bottom, and printing the
// message here instead of attaching it to the diagnostic ensures that we only print
// it once instead of repeating it for each diagnostic. Prints to stderr to prevent
// the message from being captured by tools parsing the normal output.
let message = "Panic during linting indicates a bug in Ruff. If you could open an issue at:
https://github.com/astral-sh/ruff/issues/new?title=%5BLinter%20panic%5D
...with the relevant file contents, the `pyproject.toml` settings, and the stack trace above, we'd be very appreciative!
";
error!("{message}");
return Ok(ExitStatus::Error);
error!("{message}");
return Ok(ExitStatus::Error);
}
if cli.diff {
// If we're printing a diff, we always want to exit non-zero if there are
// any fixable violations (since we've printed the diff, but not applied the
// fixes).
if !diagnostics.fixed.is_empty() {
return Ok(ExitStatus::Failure);
}
if cli.diff {
// If we're printing a diff, we always want to exit non-zero if there are
// any fixable violations (since we've printed the diff, but not applied the
// fixes).
} else if fix_only {
// If we're only fixing, we want to exit zero (since we've fixed all fixable
// violations), unless we're explicitly asked to exit non-zero on fix.
if cli.exit_non_zero_on_fix {
if !diagnostics.fixed.is_empty() {
return Ok(ExitStatus::Failure);
}
} else if fix_only {
// If we're only fixing, we want to exit zero (since we've fixed all fixable
// violations), unless we're explicitly asked to exit non-zero on fix.
if cli.exit_non_zero_on_fix {
if !diagnostics.fixed.is_empty() {
return Ok(ExitStatus::Failure);
}
}
} else {
// If we're running the linter (not just fixing), we want to exit non-zero if
// there are any violations, unless we're explicitly asked to exit zero on
// fix.
if cli.exit_non_zero_on_fix {
if !diagnostics.fixed.is_empty() || !diagnostics.inner.is_empty() {
return Ok(ExitStatus::Failure);
}
} else {
// If we're running the linter (not just fixing), we want to exit non-zero if
// there are any violations, unless we're explicitly asked to exit zero on
// fix.
if cli.exit_non_zero_on_fix {
if !diagnostics.fixed.is_empty() || !diagnostics.inner.is_empty() {
return Ok(ExitStatus::Failure);
}
} else {
if !diagnostics.inner.is_empty() {
return Ok(ExitStatus::Failure);
}
if !diagnostics.inner.is_empty() {
return Ok(ExitStatus::Failure);
}
}
}
@@ -79,7 +79,6 @@ impl ModuleName {
///
/// assert_eq!(ModuleName::new_static("foo.bar.baz").unwrap().components().collect::<Vec<_>>(), vec!["foo", "bar", "baz"]);
/// ```
#[must_use]
pub fn components(&self) -> impl DoubleEndedIterator<Item = &str> {
self.0.split('.')
}
+1 -1
View File
@@ -708,7 +708,7 @@ fn builtins_symbol_impl<'db>(
resolver_environment,
&ModuleName::new_static("__builtins__").unwrap(),
)
.and_then(&resolver)
.and_then(resolver)
.or_else(|| {
resolve_module_confident(db, resolver_environment, &KnownModule::Builtins.name())
.and_then(resolver)
@@ -538,7 +538,7 @@ impl Drop for TypeDetailGuard<'_, '_, '_, '_> {
fn drop(&mut self) {
// The fallibility here is primarily retrieving `TypeWriter::Details`
// everything else is ideally-never-fails pedantry (yay for pedantry!)
if let TypeWriter::Details(details) = &mut self.inner
if let TypeWriter::Details(details) = &mut *self.inner
&& let Some(start) = self.start
&& let Some(payload) = self.payload.take()
{
@@ -209,7 +209,7 @@ fn next_auto_value<'db>(
if last <= 0 {
Type::int_literal(1)
} else {
let shift = i64::BITS - last.leading_zeros();
let shift = last.cast_unsigned().bit_width();
1_u64
.checked_shl(shift)
.and_then(|value| i64::try_from(value).ok())
+1 -1
View File
@@ -1,2 +1,2 @@
[toolchain]
channel = "1.98.0"
channel = "1.99.0"