🐛 fix(mirror): drop the unreachable parent fallback - #2189
Merged
Conversation
A requirements include resolved its target against `parent()` with a `.` fallback for the `None` case. Nothing can take that branch, so the coverage gate reported a line no input reaches, and the closure behind `unwrap_or_else` is what made it uncoverable rather than merely untested. `Path::parent` answers `None` only for an empty path or one that is nothing but a root or a prefix, and every file on the include stack came from `requirement_file`, which reads it first. A root is a directory and an empty path names nothing, so neither survives that read. The call now says so through an `expect`, matching how the loop above already states its stack invariant, and a bare filename still keeps the empty parent that joins to its sibling. Three tests pin the refusal the argument rests on, at the top level for both shapes and through an include, so the invariant is checked rather than asserted.
Merging this PR will not alter performance
Comparing Footnotes
|
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.
A requirements include resolved its target against
file.path.parent()with a.fallback for theNonecase. No input reaches that branch, so #2162 cannot hold main at 100%: a test can neither cover the line nor remove it. What makes it uncoverable rather than untested is the closure insideunwrap_or_else, a function in this crate that nothing calls. Anexpecttakes a&strand leaves no such function behind.I treated the deletion as something to prove rather than to take on the issue's word, and the proof came out stronger than the issue states.
Path::parentanswersNonefor an empty path, or one that is nothing but a root or a prefix, and for nothing else. A barerequirements.txtyieldsSome(""), notNone, and that empty parent joins to the sibling path this code wants. Every file on the include stack came fromrequirement_file, which callsread_to_stringbefore the file joins the stack. A root and a drive prefix are directories, and an empty path names nothing, so none of them survives that read. The property generalises: any path with no parent denotes a root, a prefix, or nothing, and none of those reads as a regular file. It rests on no enumeration of/and""as special cases.Three tests pin the refusal the argument depends on, and they passed against unmodified
e64cc8308before the fallback came out, which is what makes them evidence rather than decoration. Two cover the top level, where the path arrives straight from configuration, and one covers an include of-r /, where an absolute target replaces the parent during the join. Those are the only two ways to construct aRequirementFile.The call now states the invariant through
expect, matching the loop above it, which already saysexpect("the stack has a completed file")for its own stack invariant. Every input that can reach the call behaves as before, because the tests show that no input with aNoneparent gets that far. The difference lives in a state something earlier refuses.The coverage numbers confirm that mechanism rather than just agreeing with it. Before the change
llvm-covreportedselection.rswith 55 functions, one of them missed, and one missed line. After it, 54 functions, none missed, and no missed lines. The function count falls by exactly one, which is the closure going away and taking the uncoverable line with it, so the line leaves the report because it stopped existing.A workspace grep finds no other
parent().unwrap_oranywhere. The three remainingunwrap_orcalls in this file take a different shape and stay: two default a string scan when no delimiter is present, which ordinary lines do, and one defaults an absent digest. None stands in for an unreachable state.Closes #2180