Skip to content

test(features): a sweep's exemption covers a LANG it names outside the loop #1480

Description

@dekobon

Summary

check-test-lang-gates.py exempts a sweep from the per-feature check on
the strength of a bare is_enabled / into_enum_iter token
(SWEEP_RE). The exemption is sound for the languages a sweep
iterates — the runtime filter skips the disabled ones — but it also
covers a language the sweep names outside the loop, which no filter can
skip.

The pin that exists for exactly this (hardcoded) is populated only
from *Parser / *Code type names, not from a LANG value:

// Passes the gate today. Panics under `--features python`.
#[cfg(any(feature = "python", feature = "rust"))]
#[test]
fn sweep_that_also_parses_rust() {
    if !LANG::Python.is_enabled() {
        return;
    }
    let _ = analyze(Source::new(LANG::Rust, src), Default::default());
}

--fix would write that same any(...) gate.

Why it is latent

All 16 sweep-only tests in the tree filter per language and parse only
the loop variable. Verified by reading each:
c_family_space_names_tests.rs:210,302,347, abc.rs, cognitive.rs,
nargs.rs, langs.rs, and the four parity sweeps. Nothing is wrong
today.

Why the obvious fix does not work

Pinning every surviving LANG::X literal in a sweep body was tried and
reverted: it breaks 22 items and 8 self-tests, because a sweep's row
table
is frequently written as LANG::X literals —

for (lang, src) in [(LANG::C, C_SRC), (LANG::Cpp, CPP_SRC)] {
    if !lang.is_enabled() { continue; }

— and those literals are skipped by the filter. The gate cannot
currently tell a literal inside the iterated collection from one outside
the loop, and that distinction is the whole fix.

What would fix it

Track the extent of the iterated collection (the for header's
expression, or the array literal it destructures) and pin only the
LANG::X mentions outside it. Alternatively, require is_enabled to
appear in filter position (.filter(, if !lang.is_enabled()) over an
iterated binding, rather than accepting the bare token anywhere in the
body.

Either is a real change to the scan with real regression risk, which is
why it was not folded into #1478.

Meanwhile

The boundary is documented in .claude/rules/testing.md under "A sweep
still needs the parsers it hardcodes": the pin covers a parser named as
a type and nothing else, and a fixed-parser call written
check_metrics::<RustParser> is pinned correctly.

Found by a review of PR #1479.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions