Skip to content

Add unused items pass#29431

Draft
mohammadfawaz wants to merge 1 commit into
masterfrom
mohammadfawaz/unused_items
Draft

Add unused items pass#29431
mohammadfawaz wants to merge 1 commit into
masterfrom
mohammadfawaz/unused_items

Conversation

@mohammadfawaz

@mohammadfawaz mohammadfawaz commented May 19, 2026

Copy link
Copy Markdown
Collaborator

Adds an UnusedItems warning pass to the compiler. Runs after TypeChecking and emits rustc-style dead_code / unused_variables / unused_imports diagnostics under the UNU code prefix.

What's checked

Item Warned?
Function (non-entry, non-view, non-@test)
Struct (non-record) ✅ (incl. transitive deadness)
const (any scope)
Import
Local let / param / loop iter / const generic
_-prefixed binding that was read
Record ❌ (public surface)
Struct/record field ❌ (too noisy without dataflow + opt-out)
Mapping ❌ (access via intrinsics/storage ops not tracked)
Storage variable ❌ (same)
Interface / function prototype / record prototype

Fields, mappings, and storage variables share one future unlock: data-flow-aware "is this ever read/written" tracking + an @allow_unused attribute for the legitimate false-positive cases.

Leading-_ rules

Mirroring rustc's _x convention. Whether _ is permitted depends on whether the name reaches the Aleo VM — if it does, snarkVM rejects identifiers that do not start with a letter, so we reject at compile time too. Allowed positions silence the corresponding unused_* warning.

Position Allowed? Effect / rejection
Local let binding Silences unused_variable
Tuple-pattern element Silences unused_variable
Local const Silences unused_const
Top-level / module const Silences unused_const
Loop iteration variable Silences unused_variable
Function parameter (non-entry, non-view, non-@test) Silences unused_variable. Param names don't reach the VM (renamed to r0, r1, …).
Const-generic parameter Silences unused_variable. Monomorphized away.
Variant::Fn (free fn) name Silences unused_function. Force-inlined so the name never reaches the VM.
Variant::FinalFn (final fn) name Silences unused_function. Always inlined.
Interface name Interfaces are Leo-only — no rejection, no warning.
Entry-point function name (fn inside program { … }) NameValidation rejects → ENV03711002.
view fn name NameValidation rejects → ENV03711002. Externally callable and emitted verbatim (never inlined), like an entry point.
Struct / record name NameValidation rejects → ENV03711002.
Struct / record field name NameValidation rejects → ENV03711002.
Mapping name NameValidation rejects → ENV03711002.
Storage variable name NameValidation rejects → ENV03711002.
Program name (program X.aleo) NameValidation rejects → ENV03711002.
Binding name matching a bare-callable intrinsic (_self_caller, _block_height, etc.) Parser rejects → EPAR0370056. The parser dispatches _self_caller() to the intrinsic before any scope lookup, so a same-named local would be silently shadowed.
@no_inline on a _-prefixed Variant::Fn Type-checker rejects → ETYC0372192. The two annotations directly contradict.

Bonus: reading a _-prefixed local (which would defeat the silencing marker) emits WUNU03714006used binding \x` whose name begins with ```.

Architecture

The pass is structured as three phases, all driven by the standard AstVisitor / UnitVisitor traits:

  1. UseCollector walks the AST once: populates used_imports / used_globals, tracks lexical scopes, emits body-level warnings as each scope drains, and records composite member-dependency edges into a local graph (composite_deps / composite_roots).
  2. Pure reachability scan over that dependency graph from "live roots" (records + library top-level structs + any composite directly referenced from user code).
  3. UnusedChecker walks the AST again (without descending into bodies) and emits warnings for unused top-level items and imports.

The two visitors share state via an owned CollectedUses struct passed by reference. NameValidation (a sibling pass that runs before TypeChecking) handles all leading-_ rejections in positions where the name reaches the Aleo VM.

@mohammadfawaz mohammadfawaz self-assigned this May 19, 2026
@codspeed-hq

codspeed-hq Bot commented May 19, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 17 untouched benchmarks


Comparing mohammadfawaz/unused_items (8fa54ac) with master (2d234d7)

Open in CodSpeed

@mohammadfawaz mohammadfawaz force-pushed the mohammadfawaz/unused_items branch 2 times, most recently from c9ad543 to 1d530b0 Compare May 19, 2026 22:14
@mohammadfawaz mohammadfawaz added 🚀 feature A new feature. 🧱 Core Compiler Anything related to the core compiler including parsing, analysis, transforms, codegen, etc. labels May 20, 2026
@mohammadfawaz mohammadfawaz force-pushed the mohammadfawaz/unused_items branch 4 times, most recently from 212cdfa to 5cd4474 Compare May 25, 2026 14:11
@mohammadfawaz mohammadfawaz force-pushed the mohammadfawaz/unused_items branch 5 times, most recently from 73fd3ba to 548b070 Compare May 28, 2026 17:38
@mohammadfawaz mohammadfawaz force-pushed the mohammadfawaz/unused_items branch 14 times, most recently from f1baea5 to 7c246b6 Compare June 15, 2026 20:32
Emit warnings for items that are never used, mirroring rustc's `dead_code`,
`unused_variables`, `unused_imports`, and `unused_const` lints:

- Unused functions (non-entry, non-`view`, non-`@test`), structs, top-level
  and local `const`s, local bindings (`let`, params, loop vars), and imports.
- A leading `_` marks an item intentionally unused and silences the warning;
  `_`-prefixed `fn`s are force-inlined so the name never reaches the VM.
- Names emitted into Aleo bytecode (program, entry-point and `view fn`,
  struct/record and their fields, mappings, storage variables) are rejected if
  they start with `_`, and bindings colliding with a bare-callable intrinsic
  are rejected.

Dead program functions no longer double-report their unused params/locals on
top of the function-unused warning, and local-binding lookups use an O(1)
per-name index instead of an O(n) reverse scan.
@mohammadfawaz mohammadfawaz force-pushed the mohammadfawaz/unused_items branch from 7c246b6 to 8fa54ac Compare June 15, 2026 20:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🧱 Core Compiler Anything related to the core compiler including parsing, analysis, transforms, codegen, etc. 🚀 feature A new feature.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant