Detect duplicate sibling modules in recursive module groups#19913
Detect duplicate sibling modules in recursive module groups#19913T-Gro wants to merge 4 commits into
Conversation
Add 7 tests in ErrorMessages/ModuleTests.fs locking the desired behavior: duplicate sibling modules in a 'module rec' / 'namespace rec' must produce FS0037 at type-check time, not FS2014 from IL emit. Filtered run (--filter-class ErrorMessages.Modules): total: 20, failed: 3, succeeded: 17 RED (positive, fail today): - Recursive module with duplicate sibling modules emits FS0037 - Recursive namespace with duplicate sibling modules emits FS0037 - Recursive module nested siblings with duplicate name emit FS0037 GREEN (negative regression guards, pass today): - Recursive module nested cousins with same name compile - Non-recursive module with duplicate sibling modules still emits FS0037 - Single file with two namespace fragments and different modules compiles - Recursive module siblings differing only in case compile Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ublish time In `module rec` / `namespace rec` groups all siblings share the same envInitial during Phase1A, so the existing CheckForDuplicateModule call in TcTyconDefnCore_Phase1A_BuildInitialModule cannot see them. Move the check to the Phase1AB publish point where envAbove's accumulator already contains earlier-published siblings. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ostic Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
❗ Release notes requiredYou can open this PR in browser to add release notes: open in github.dev
|
T-Gro
left a comment
There was a problem hiding this comment.
Review: LGTM – clean, well-targeted fix.
Summary
The fix correctly places a CheckForDuplicateModule call in Phase1AB's publish loop where envAbove's mutable accumulator already reflects previously-published siblings. Since MutRecShapes.computeEnvs uses List.map (sequential, left-to-right) and PublishModuleDefn mutates the accumulator, the second duplicate will see the first when it checks. This mirrors the analogous CheckForDuplicateConcreteType pattern for tycons a few lines below.
Details
| Aspect | Assessment |
|---|---|
| Correctness | Relies on sequential List.map + mutable accumulator - same pattern as tycon duplicate check at line 4115 |
| Non-recursive regression | Test confirms non-recursive case still works (different code path) |
| False positives | Cousins (same name, different parent) pass; case-differing siblings pass |
| Error UX | Reuses existing FS0037 Duplicate definition of type or module - consistent |
| Test coverage | 7 tests: 3 positive (must-fail) + 4 negative (must-pass) regression guards |
| Release notes | Clear, links issue and PR |
No concerns. Nice fix!
| module Foobar = let x = 1 | ||
| module Foobar = let y = 2 |
There was a problem hiding this comment.
Could you add a test showing whether the second module is analyzed properly and y is reported to the sink?
Fixes #6694