Repository navigation
Refuse a function defined twice in one file - #25
Merged
Merged
Conversation
The evaluator takes the last definition and says nothing, so a replacement written above the body it was meant to replace leaves the old body running and the file reads as though it does not. spool had that in two files at once and it went through a passing test suite, a passing source gate and passing CI. The check is in the pass that already walks every top-level FnDecl to register its name, so it costs one map. Both checkers get it, and the message is byte-identical between them, which the differential harness requires. The message names the winner, because the whole failure is someone believing the other one won, and it points at the redefinition rather than the original, which is the line to go look at. There is no conditional compilation in this language, so there is no reading under which a second declaration of one name in one file is meant. Swept 458 .tw files across twill, std, testdata and the six satellites: no false positives, and it catches spool's bug at the commit before the fix. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
BUGS.md entry 11, with what it cost, why the prelude pass let it through and what the sweep measured. The Open section had it as of an hour ago with the fix described as obvious and not written. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
#24 wrote the footgun down. This is the fix.
The evaluator takes the last definition and says nothing, so a replacement written above the body it was meant to replace leaves the old body running and the file reads as though it does not. spool shipped that in two files during the 1.9.0 sort adoption — through a passing test suite, a passing source gate and passing CI, because nothing in any of them looked at whether a name was defined twice.
Where it goes
In the prelude pass that already walks every top-level
FnDeclto register its name, so it costs one map and no extra traversal. Both checkers get it,internal/checker/checker.goandsrc/check.tw, and the two messages are byte-identical — the differential harness compares stdout exactly, so parity was not optional:The message names the winner, because the whole failure is someone believing the other one won, and it points at the redefinition rather than the original, which is the line to go look at.
What was measured, not assumed
spool@HEAD~1:src/strutil.tw, the actual file before the fix:sort_strs is already defined on line 338..twfiles acrosssrc,std,testdata,examplesand all six satellites. Zero hits.There is no conditional compilation in twill, so the readings under which somebody means a second declaration — a platform variant, a debug build — do not exist. That is why the false-positive rate should be zero, and it is.
Tests
internal/checker/redefine_test.go, ten of them: the message, the line number (2, not 1), the severity, one report per redefinition so deleting one does not hide the next, spool's exact shape, and the two things that must not trip it — a local shadowing a function name, and a function deliberately shadowing a builtin, which twill supports and which this must not break.Also moves the entry out of
docs/BUGS.md's Open section into the numbered record as entry 11, and adds the Unreleased changelog note.🤖 Generated with Claude Code