result is checked wherever a clause writes it - #971
Merged
Conversation
I went looking for the machinery that would settle `transfer`'s two remaining
`ensures` clauses, needed the definition `result` binds to, found two copies of
that lookup, and found that one of them was wrong.
The type checker's copy matched expressions with a wildcard. Everything that
fell through it left `result` with no type, an unknown type agrees with
everything, and the clause went through in silence:
ok => result == "text" DEED4001
ok => use_it(|x: Int| result == "text") accepted
Both are in a function returning `Int`. The second one is caught by the
property runner instead, as DEED6003, "twice did not keep this promise", which
sends a reader to look at the postcondition when the mistake is a type error
two characters to the right.
The lookup moves to `deed-resolve`, which is where a question about what a name
refers to belongs, and is written on `deed_ast::children`, which matches
without a wildcard. The interpreter had already been fixed for exactly this
once, in the change that gave `children` its no-wildcard match; the checker's
copy predates it and nobody had a reason to look at both. That is what having
two of them cost, and there is one now.
Six shapes the wildcard swallowed get a case each, in both directions: the
clause is rejected when the type is wrong and accepted when it is right, in a
closure, a list, a branch, a match arm, a block and a walk. Break-verified by
declining to descend into a closure again, which fails those and the two
interpreter tests from the earlier fix.
Nothing in `examples/` or `std/` relied on the hole.
The header of `checking.rs` opened by counting its own tests, said ninety-one,
and there are a hundred and thirty-seven. It no longer quotes a total; the
claim worth making about that file is the one underneath, which does not
depend on how many tests there are.
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.
I went looking for the machinery that would settle
transfer's two remainingensuresclauses, needed the definitionresultbinds to, found two copies of that lookup, and found that one of them was wrong.The hole
The type checker's copy matched expressions with a wildcard. Everything that fell through it left
resultwith no type, an unknown type agrees with everything, and the clause went through in silence:Both return
Int. The second is caught by the property runner instead, asDEED6003, "twicedid not keep this promise" — which sends a reader to look at the postcondition when the mistake is a type error two characters to the right. It is the classDEED6006's own note describes: either this file was not checked or the check has a hole.The fix
The lookup moves to
deed-resolve— where a question about what a name refers to belongs — and is written ondeed_ast::children, which matches without a wildcard, so a new kind of expression is a build error rather than a clause that quietly stops being checked.The interpreter had already been fixed for exactly this once, in the change that gave
childrenits no-wildcard match. The checker's copy predates it and nobody had a reason to look at both. That is what having two of them cost; there is one now.Held by
result_is_checked_wherever_in_a_clause_it_is_writtenanda_clause_that_reads_result_correctly_is_accepted_in_every_shape: six shapes the wildcard swallowed — a closure, a list, a branch, a match arm, a block, a walk — in both directions, so the first cannot pass on a checker that rejects all six for a reason of its own.Break-verified by declining to descend into a closure again: that fails both new tests and the two interpreter tests from the earlier fix, which is the evidence the lookup is now genuinely shared.
Nothing in
examples/orstd/relied on the hole; no obligation moves.While here
The header of
checking.rsopened by counting its own tests, said ninety-one, and there are a hundred and thirty-seven. It no longer quotes a total. The claim worth making about that file is the one underneath it — that no test there settles for asserting that something failed — and that one does not depend on how many tests there are.