Skip to content

check: refuse a module that declares a top-level name twice (Closes #10421) - #10442

Draft
gHashTag wants to merge 4 commits into
masterfrom
fix/check-refuse-duplicate-toplevel
Draft

gHashTag wants to merge 4 commits into
masterfrom
fix/check-refuse-duplicate-toplevel

Conversation

@gHashTag

Copy link
Copy Markdown
Owner

Summary

t27c check now fails with an error when a module declares one top-level const, var, fn, struct, enum or test name more than once in one namespace. Before, a duplicate const/var passed silently and a duplicate fn got only a warning, while the backends disagreed on which copy wins (gen-js keeps the first value, gen-c reads the last, gen-verilog emits two parameters, test-report is blocked by zig).

Closes #10421. Refs #5980 (the self-hosted core already refuses this with E_NAME; this brings the Rust front end to the same rule).

What changed

  • bootstrap/src/compiler.rs: duplicate_top_level_decls now also collects module-level const / var (only ast.children, so a local const inside a body stays scope). In typecheck_ast a same-namespace duplicate is counted as an error. A duplicated bench keeps its warning; the "type and function share a name" and "lowered collision" warnings are unchanged.
  • bootstrap/stage0/FROZEN_HASH: re-sealed for the compiler.rs change.
  • bootstrap/tests/duplicate_declarations.rs: assertions moved from "warning" to "error"; the obsolete "finding is a warning and does not change the exit code" test is removed; the clean fixture gained two sibling functions that each declare a local const K (negative control).
  • bootstrap/tests/fixtures/duplicate_toplevel/: refuse/ has one fixture per kind (dup_const, dup_var, dup_fn, dup_struct, dup_test) plus dup_const_and_fn, the probe from the issue; accept/sibling_blocks.t27 is the negative control.

Lab run (Railway lab, t27c built from this branch)

  • All 6 refuse fixtures: rc 1, with error: \ ` is declared N times -- a redeclaration is refused ...`.
  • accept/sibling_blocks.t27: rc 0, no "is declared" line.
  • The probe on the previous master binary: Typecheck OK (0 errors, 1 warnings), rc 0 (the control showing the gap was real).
  • gen-c and gen-js on dup_const.t27 now exit 1 too, since they run the same check.
  • Corpus: t27c check over all 2262 specs on this branch: 0 refused, and the only "declared N times" warnings are the same two pre-existing duplicated bench names (specs/igla/race/backend.t27, specs/igla/race/cordic_top.t27). Master baseline: 2261 specs, 0 refused, same 2 warnings. So 0 new failures.

Out of scope

  • Repairing the two duplicated bench names and promoting that case to an error.
  • Any backend change: refusing the input is the fix.

Foreign-language budget

This edits existing Rust. Net foreign lines: compiler.rs +11/-1 (plus the seal line), the Rust test file +2/-14; lefthook foreign-budget passed without --no-verify. This PR is a draft and waits for the owner's owner-approved-foreign label. Not to be merged before that.

🤖 Generated with Claude Code

gHashTag and others added 2 commits October 18, 2026 18:28
…ct, enum or test twice (Refs #10421, #5980)

gen-js keeps the first of two consts and gen-c reads the last, so check now
fails with an error instead of staying silent (const, var) or warning (fn,
struct, enum, test). A bench keeps its warning: two corpus specs still carry one.
Fixtures: refuse/ per kind, accept/sibling_blocks as the negative control.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-18 11:52:05 UTC

Summary

Status Count
Total Open PRs 50
PRs with Failing Checks 50
PRs with All Checks Green 0
READY 0
FAILING 50
PENDING 0
NO CHECKS YET 0

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=51db3c0b258e != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

…he refused fixtures (Refs #10421)

spec-guards' duplicate-declarations self-check recognises a duplicate by the
sentence "every backend rejects a redeclaration"; the new error said something
else, so the planted-duplicate and duplicated-test cases read 0. The sentence
is also true now that check refuses the input, so the error uses it again.

emit-bitexact requires every tracked .t27 to generate with some backend. The
ten spec fixtures that a duplicated top-level name now makes a typecheck error
(six new ones, four in core_selfhost/refuse) are ledgered in
specs_generate_baseline.txt as "not a debt", the way the other typecheck
refuse fixtures already are.

compiler.rs: one string changed, net 0 lines. FROZEN_HASH re-sealed.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…efs #10421)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-18 12:11:53 UTC

Summary

Status Count
Total Open PRs 50
PRs with Failing Checks 50
PRs with All Checks Green 0
READY 0
FAILING 50
PENDING 0
NO CHECKS YET 0

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=092ec34c7ce7 != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

This was referenced Oct 18, 2026

This branch has not been deployed

No deployments
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.

check: refuse a module that declares one top-level name twice (gen-js keeps the first const, gen-c the last)

1 participant