Skip to content

Allow and document clippy::drain_collect - #8500

Merged
youknowone merged 1 commit into
RustPython:mainfrom
joshuamegnauth54:clippy-drain_collect
Aug 12, 2026
Merged

Allow and document clippy::drain_collect#8500
youknowone merged 1 commit into
RustPython:mainfrom
joshuamegnauth54:clippy-drain_collect

Conversation

@joshuamegnauth54

@joshuamegnauth54 joshuamegnauth54 commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

RustPython's tail call machinery pre-allocates and reuses a vector. The code drains the vector into a new vector which is stored elsewhere.

Clippy warns that this pattern causes a spurious location. Clippy is usually right that this pattern is suspect, but in this case the initial vector is reused so we want to keep the initial location.

Summary

  • Silences a clippy lint about collecting a drain iterator
  • Documents why this behavior is expected

Summary by CodeRabbit

  • Refactor
    • Simplified character encoding logic while preserving existing encoding behavior.
    • Improved runtime handling of pending references during optimized call execution.
  • Performance
    • Reduced unnecessary memory allocation in internal execution paths, supporting more efficient runtime performance.
  • Reliability
    • Maintained consistent behavior across initial, nested, and resumed calls.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro Plus

Run ID: 3f7cb52a-f8d4-4426-9e50-2fea90e7c0d7

📥 Commits

Reviewing files that changed from the base of the PR and between 03bfd70 and ef45416.

📒 Files selected for processing (1)
  • crates/vm/src/vm/mod.rs

📝 Walkthrough

Walkthrough

The PR simplifies wchar_len calculation in codec error handling and adds targeted Clippy allowances for intentional drain-and-collect operations in the VM trampoline.

Changes

Tail-call reference handling

Layer / File(s) Summary
Trampoline reference allowances
crates/vm/src/vm/mod.rs
Targeted Clippy allowances cover four tail-call reference extraction sites, including exception resumption.

Code-page error handling

Layer / File(s) Summary
Wchar length calculation
crates/vm/src/stdlib/_codecs.rs
wchar_len now uses a direct conditional expression. Surrogate handling and UTF-16 length calculation remain unchanged.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Possibly related PRs

Suggested reviewers: youknowone, shaharnaveh

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary change: allowing and documenting clippy::drain_collect.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/vm/src/vm/mod.rs`:
- Line 1471: Replace the remaining pending tail-call reference
`.drain(..).collect()` in the exception-unwind tail-call branch with the same
`mem::take` ownership transfer used by `initial_refs` and the analogous
branches. Preserve the existing behavior and run `cargo clippy` afterward.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro Plus

Run ID: 34fd5b4d-baa6-4d5c-b1e3-c931476ab6a6

📥 Commits

Reviewing files that changed from the base of the PR and between 81df1ff and 03bfd70.

📒 Files selected for processing (2)
  • crates/vm/src/stdlib/_codecs.rs
  • crates/vm/src/vm/mod.rs

Comment thread crates/vm/src/vm/mod.rs Outdated
@joshuamegnauth54
joshuamegnauth54 marked this pull request as draft August 12, 2026 02:07

@ShaharNaveh ShaharNaveh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

great!

not a blocker: can we enforce this with the clippy rules if it's not already been done?

RustPython's tail call machinery pre-allocates and reuses a vector.
The code drains the vector into a new vector which is stored elsewhere.

Clippy warns that this pattern causes a spurious location. Clippy is
usually right that this pattern is suspect, but in this case the initial
vector is reused so we want to keep the initial location.
@joshuamegnauth54 joshuamegnauth54 changed the title perf: Fix clippy::drain_collect Allow and document clippy::drain_collect Aug 12, 2026
@joshuamegnauth54
joshuamegnauth54 marked this pull request as ready for review August 12, 2026 15:28
@joshuamegnauth54

Copy link
Copy Markdown
Contributor Author

@ShaharNaveh I went through the code in depth to check if the lint was necessary. It turns out that Clippy is overzealous here. The original code pre-allocates a buffer to reuse. The drain/collect idiom is intentional and correct. Instead, I documented the behavior and allowed the lint so that anyone else who encounters it knows not to fix the lint. I also fixed a totally unrelated but small lint. 😁

I used #[allow] instead of #[expect] because the lint doesn't trigger on my stable compiler but does trigger on nightly. CI would fail with #[expect].

@ShaharNaveh

Copy link
Copy Markdown
Contributor

@ShaharNaveh I went through the code in depth to check if the lint was necessary. It turns out that Clippy is overzealous here. The original code pre-allocates a buffer to reuse. The drain/collect idiom is intentional and correct. Instead, I documented the behavior and allowed the lint so that anyone else who encounters it knows not to fix the lint. I also fixed a totally unrelated but small lint. 😁

I used #[allow] instead of #[expect] because the lint doesn't trigger on my stable compiler but does trigger on nightly. CI would fail with #[expect].

tysm for looking into it!

@ShaharNaveh

Copy link
Copy Markdown
Contributor

@joshuamegnauth54 can we still add this rule? so future places would get flagged

@ShaharNaveh ShaharNaveh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

adding the rule is not a blocker (for me)

@fanninpm

Copy link
Copy Markdown
Contributor

I used #[allow] instead of #[expect] because the lint doesn't trigger on my stable compiler but does trigger on nightly. CI would fail with #[expect].

@coderabbitai Can #[expect] be used within #[cfg] so that #[expect] only applies when built with the nightly compiler?

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '== Rust toolchain and project policy files =='
fd -HI -t f '^(rust-toolchain(\.toml)?|Cargo\.toml|clippy\.toml|CONTRIBUTING\.md|README\.md)$' . \
  | sed -n '1,160p'

printf '%s\n' '== Compiler-version and nightly configuration references =='
rg -n -i -C 3 \
  '(rust-version|rustup|nightly|stable|rustversion|check-cfg|unexpected_cfgs|drain_collect)' \
  -g 'Cargo.toml' -g 'rust-toolchain*' -g 'clippy.toml' -g '*.rs' -g '*.md' . \
  | sed -n '1,280p'

printf '%s\n' '== Tail-call source map =='
ast-grep outline crates/vm/src/vm/mod.rs --items all --match 'trampoline|tail|call' --view expanded || true

printf '%s\n' '== Changed lines in relevant files =='
git diff -- crates/vm/src/vm/mod.rs crates/vm/src/stdlib/_codecs.rs

Length of output: 18513


🤖 web_search executed:

site:doc.rust-lang.org/reference conditional compilation cfg Rust built-in cfg nightly stable compiler channel

Length of output: 5066


🤖 web_search executed:

site:doc.rust-lang.org rustc lint expect attribute unfulfilled_lint_expect documentation

Length of output: 8212


@fanninpm Yes, but Rust does not define a built-in cfg predicate for the compiler channel.

This attribute is valid if the build defines a custom nightly configuration option:

#[cfg_attr(nightly, expect(clippy::drain_collect))]
let refs: Vec<_> = refs.drain(..).collect();

A build script or CI must then define nightly only for nightly builds. A build script must also declare the option for check-cfg:

println!("cargo::rustc-check-cfg=cfg(nightly)");
println!("cargo::rustc-cfg=nightly");

The second line must run only when the selected rustc is nightly.

I do not recommend this for this PR. RustPython selects stable in rust-toolchain.toml and supports the latest stable Rust. The Clippy lint does not trigger consistently across those compiler versions. The documented #[allow(clippy::drain_collect)] therefore states the intended behavior without adding custom compiler-channel detection. #[expect] is best when the lint is expected to trigger on every supported toolchain.

You are interacting with an AI system.

@fanninpm

Copy link
Copy Markdown
Contributor

It turns out that Clippy is overzealous here. The original code pre-allocates a buffer to reuse. The drain/collect idiom is intentional and correct.

See rust-lang/rust-clippy#12410

@joshuamegnauth54

Copy link
Copy Markdown
Contributor Author

@ShaharNaveh Do you mean enabling the lint or denying the lint? The lint should already be enabled by default, yet I'm unsure why it didn't trigger. Here's a Playground lint that demonstrates that it triggers on stable. 🤔

@youknowone
youknowone merged commit 3a98ef7 into RustPython:main Aug 12, 2026
27 checks passed
@ShaharNaveh

Copy link
Copy Markdown
Contributor

@ShaharNaveh Do you mean enabling the lint or denying the lint? The lint should already be enabled by default, yet I'm unsure why it didn't trigger. Here's a Playground lint that demonstrates that it triggers on stable. 🤔

oh, it didn't trigger due to clippy bug, nvm...

tysm!

@joshuamegnauth54
joshuamegnauth54 deleted the clippy-drain_collect branch August 13, 2026 17:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants