[Bug] A Rust impl block reads as private although rust.scm says it inherits its target's visibility

Open
#2,389 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
52/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
python, rust
Domain
devtools

Research direction

This spans packages/core/src/repowise/core/ingestion/queries/rust.scm and analyzer.py, with refinement behavior modeled by the fix in #2376. First confirm #2388 lands, then inspect the four impl_item query shapes and the existing Rust visibility refinement chain. Add fixtures for public and private targets across all shapes, plus the unused_export regression fixture; done means visibility is inherited without reporting impl blocks as unused exports.

Written by the indexing model from the issue text.

Description

Summary

rust.scm states that an impl block inherits its visibility from the type or trait it implements. It does not. No visibility is captured, the modifier text is empty, and every impl block in every Rust repository reads private, including the roughly 6,600 that implement a pub type.

Mechanism

The query captures the target type's name and nothing else, and says so in a comment that describes an inheritance that is never performed.

packages/core/src/repowise/core/ingestion/queries/rust.scm:71-76

; impl block — the "type" field identifies what is being implemented
; impl does NOT need visibility capture (inherits from type/trait)
(impl_item
  type: (type_identifier) @symbol.name
) @symbol.def

The other three impl_item patterns at :77-95, covering generic, scoped and reference target types, capture no @symbol.modifiers either. With no modifier text, rust_visibility returns private, so the "inherits from type/trait" claim resolves to a constant.

This is the same shape as the trait-item defect fixed in #2376, where Rust forbids a visibility modifier on a trait item and rust_visibility therefore read private for every method of a pub trait. That fix added refine_rust_visibility, which reads the enclosing trait_item's own modifier and is wired into the existing cpp / csharp / ts refinement chain. It matches an exact node shape rather than walking ancestors, and it is the template here.

Evidence

Counted over the Rust corpus at the current commit:

repo impl symbols targeting a pub type
serde 367 213
ripgrep 442 276
rtk 68 43
goose 811 622
bevy 6,468 5,493

All 8,156 read private. On the figures above, 6,647 should read public.

Impact

Visibility is wrong on a large symbol population, which matters anywhere visibility is read: the public-surface view, unused_export eligibility, and any published-API work.

This is blocked on #2388, and landing it first would cause a regression. _detect_unused_exports skips a symbol whose visibility is not public (analyzer.py:1201), and impl is in neither _UNIVERSAL_NON_IMPORTABLE (analyzer.py:257-269) nor _UNCALLABLE_TYPE_KINDS (analyzer.py:351-358). The private reading is the only thing keeping impl blocks out of that pass. Correct the visibility while impl is still a callable kind and roughly 6,600 symbols that nothing can ever call by name become eligible to be reported as unused exports. Land the exclusion first, then this.

Done looks like

An impl block carries the visibility of the type or trait it implements, matching what rust.scm:72 already claims, following #2376's refinement-function shape.

Keep this scoped to impl_item. Do not widen it to other node types whose visibility may also be wrong; each needs its own measurement.

Tests: fixtures asserting that an impl block on a pub type reads public and one on a private type reads private, across all four target shapes the query covers (plain, generic, scoped, reference); plus a regression fixture asserting no unused_export finding is produced for an impl block whose visibility now reads public.

Note for whoever picks this up: rust.scm has two open PRs against it (#2327, #2386), both scoped to type_use captures. They do not overlap with this, but a rebase may be needed.

Dominant language
Python
Stars
6.7k
Forks
711
Avg merge
1d 13h
Merged PRs (30d)
439

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from repowise-dev/repowise

All issues in repowise-dev/repowise

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.