feat: add nargo check --fix to remove unused imports and unnecessary mut - #13390
Draft
TomAFrench wants to merge 2 commits into
Draft
feat: add nargo check --fix to remove unused imports and unnecessary mut#13390TomAFrench wants to merge 2 commits into
nargo check --fix to remove unused imports and unnecessary mut#13390TomAFrench wants to merge 2 commits into
Conversation
Adds a compiler-level rewrite that removes all imports reported unused by
the elaborator in one go, including complex composite forms: pruning
individual entries from bracketed lists (`use foo::{bar, baz}` ->
`use foo::bar`), collapsing nested lists, handling aliases and `self`
imports, and deleting fully-unused `use` items along with their line.
The core lives in `noirc_frontend::remove_unused_imports` and matches
imports by the same `(Ident, Location)` key the usage tracker records.
The LSP's "Remove unused import" quick fix now reuses this shared core
(gaining `self`-import support) instead of its own tree-pruning copy.
`nargo check --remove-unused-imports` rewrites only files belonging to
the package's own crate, and warnings for the imports it just removed
are filtered out of the report. Removal is deliberately a single round,
not a fixpoint: an import only consumed by another `use` statement's
path is revealed unused only after re-elaboration, so a second run may
remove more (documented by a dedicated test).
TomAFrench
marked this pull request as draft
July 22, 2026 14:30
Renames the flag from --remove-unused-imports to --fix and generalizes the frontend rewrite (now `noirc_frontend::fix`) to apply any warning fix that is a pure removal. Alongside unused imports it now drops `mut` modifiers the elaborator reported as unnecessary, located via the typed `VariableDoesNotNeedToBeMutable` errors that a new `check_crate_returning_frontend_errors` driver entry point exposes. The fix collector is now an AST visitor, since `mut` patterns live inside function bodies rather than at item level. The elaborator does not currently warn for never-mutated `mut` parameters; a characterization test documents that boundary.
nargo check --remove-unused-imports to prune unused importsnargo check --fix to remove unused imports and unnecessary mut
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Problem
Resolves the manual-cleanup gap around warnings whose fix is mechanical: the compiler knows exactly where every unused import and unnecessary
mutis, but fixing them meant editing them one by one (or oneusestatement at a time via the LSP quick fix).Summary
Adds a compiler-level rewrite that applies removal-only fixes in one go, exposed as
nargo check --fix(hidden flag for now). Fixes never add code — they only delete or simplify what a warning points at. Two fixes are supported:Unused imports (
noirc_frontend::fix):(Ident, Location)key the usage tracker records, so same-named imports never alias each other.use foo::{bar, spam, baz::{qux, corge}}→use foo::{bar, baz::qux}), collapses lists left with a single entry (including through nesting), understands aliases (as b) andselfimports (a list collapsing to bareselfbecomesuse foo;, not the invaliduse foo::self;).useitems are deleted together with their line, and adjacent deletions / doubled-up blank lines are cleaned so no whitespace debris is left. Rewritten trees render in canonical single-line form; runnargo fmtafterwards for style.Unnecessary
mutmodifiers:VariableDoesNotNeedToBeMutableerrors, exposed by a newcheck_crate_returning_frontend_errorsentry point innoirc_driver(the existingcheck_cratedelegates to it, behavior unchanged).mutis dropped wherever the binding lives —letbindings, tuple-destructuring patterns, nested modules. The elaborator does not currently warn for never-mutatedmutparameters; a characterization test documents that boundary and will flag if it changes.CLI:
nargo check --fixrewrites only files belonging to the package's own crate (dependencies are never touched), only when the check succeeds (no rewriting on top of compilation errors), and filters the warnings for the code it just fixed out of the report sonargo checkdoesn't warn about code that no longer exists.LSP: the "Remove unused import" quick fix now delegates to the shared core instead of carrying its own copy of the tree-pruning logic (~100 lines deduplicated), and gains
self-import removal in the process.Deliberate limitation: single round, not a fixpoint
Resolving an import's path marks its first segment as used, so an import whose only consumer is another
usestatement is only reported unused after thatuseis removed and the program re-elaborated. Each invocation fixes exactly what the current compilation reports; re-running fixes the next level of such cascades. This is intentional (a fixpoint loop could re-elaborate many times) and is documented by theimport_used_only_by_a_removed_import_is_only_removed_on_a_second_runtest.Test coverage
compiler/noirc_frontend/src/tests/fix.rs) covering composite/bracketed pruning, brace collapse (incl. nested), whole-item deletion, aliases,selfimports andselfcollapse, nested inline modules, visibility preservation, multi-lineuseitems, adjacent deletions, the cascade-over-two-runs behaviour,mutremoval fromletand tuple-pattern bindings, combined import+mutfixing in one pass, the parameter-mutboundary, and the nothing-to-fix case.self-import removal; existing quick-fix tests unchanged and passing.check_cmd.rs(warnings at other locations and non-warning diagnostics survive).Full
noirc_frontend(2225) andnoir_lsp(351) suites pass; fmt and clippy clean.