Repository navigation
Keep a static final constant's name in refinement errors - #490
Merged
Merged
Conversation
Folding replaced every resolved constant with its value, so Found showed mode == 2 where the code wrote ImageWriteParam.MODE_EXPLICIT. A constant is now replaced by its value only when the expression around it folds (MODE_EXPLICIT + 1 becomes 3); otherwise it keeps its name. The SMT encoding is unchanged: the constant is still bound to its value. The counterexample filter compares a named constant in Found with its value in the model, so mode == 2 is not repeated as a counterexample. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Collaborator
Author
|
Codex review, round 1
No findings, so nothing to fix; the review loop stops here. |
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.
Closes #488
Where the name was lost
Both paths in the issue already kept the name up to VC simplification:
Predicate.resolveStaticFinalConstants) and the client side (RefinementTypeChecker.tryStaticFinalConstantRefinement, for a field read such asint mode = ImageWriteParam.MODE_EXPLICIT;or a call argument) both build anEnumnode namedImageWriteParam.MODE_EXPLICITthat carries the value as itsresolvedLiteral;ImageWriteParam.MODE_EXPLICIT == 2.The name was dropped by the folding pass of the simplification (
VCFolding), which rewrote every resolved constant to its literal (// enum constant -> literal), whatever was around it. So Found, which is the simplified VC, showedmode == 2, while Expected, which is not simplified, kept the name.Design
The AST already has a node that holds both name and value, so no new node or context equality is needed. The only change is when folding uses the value:
VCFoldingreads a constant's value only to fold the expression around it: a binary or unary expression whose operands are all literals or constants (MODE_EXPLICIT + 1→3,Integer.MIN_VALUE < 0→true,-LIMIT), or a ternary whose condition is a boolean constant. In every other case the constant keeps its name (mode == ImageWriteParam.MODE_EXPLICIT). The constant is never rewritten to a bare literal on its own, so a derivation step never shows the value in place of a name the code wrote.A.X == A.Ywith both equal to 2 folds totrue; the name-based ruleFormat.JPG != Format.PNGkeeps applying to enums only.RefinementError.states(the counterexample filter) compares a constant in Found with its value in the model, somode == ImageWriteParam.MODE_EXPLICITdoes not also printCounterexample: mode == 2. This is a 3-line change inRefinementError; Restore alias expansion in refinement diagnostic history #295 (fix/295-alias-expansion) also touches this file, in other methods, so the two should merge cleanly.Names come only from where the source wrote them: the node is built from the field read or the spec text, never from a value. Literals the code wrote stay numbers (
requireKnownMode(2)), computed values become numbers, and the solver's counterexample values stay numbers. The SMT encoding is unchanged.Before / after (CLI,
java -jar liquidjava-verifier/target/liquidjava-verifier-0.0.36.jar <dir>)Issue reproducer (
direct()andthroughLocal()):dcm4che study task (
x_e_oss_a1_01_sliderecoder,packageline stripped, so lines are one less than in the exercise) withwParam.setProgressiveMode(ImageWriteParam.MODE_EXPLICIT);aftergetDefaultWriteParam():Unmodified task: unchanged before and after,
State Refinement Error: found tilingNotExplicit(wParam³⁰⁵) && compressionNotExplicit(wParam³⁰⁵) but expected compressionExplicit(wParam³⁰⁵) || compressionTypeSet(wParam³⁰⁵)at line 131 of the exercise. WithwParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);added:Correct! Passed Verification.before and after.Computed value,
small(ImageWriteParam.MODE_EXPLICIT + 1)with@Refinement("_ < 3"), unchanged (the value is computed, so it is a number);small(ImageWriteParam.MODE_EXPLICIT - 1)passes:Negative constant, the existing
ErrorStaticFinalConstant(requirePositive(Integer.MIN_VALUE)):Tests
TestStaticConstantNames+ fixtureErrorStaticFinalConstantName: the issue's two shapes, asserting the message and that there is no counterexample. Both fail on main.VCFoldingTest: newkeepsResolvedEnumNameWhenNothingFolds(fails on main); the two tests of resolved constants now expect the fold in one step (Config.LIMIT == 3→true,Config.LIMIT + 2 == 5→5 == 5→true) instead of an intermediate step showing the value.if#302, Constant accessed through a subclass gives "Sorts Int and Bool are incompatible" #305, Soundness: a local variable with a constant's name shadows the constant (Format.JPG read as local JPG) #321, Verifier crashes on a field or enum constant whose declaring class cannot be resolved #390, the*StaticFinal*fixtures,TestCounterexamples#staticFinalConstantHasNoCounterexampleBecauseValueIsAlreadyKnown) pass unchanged.Full verifier suite locally: 702 tests, 0 failures.
🤖 Generated with Claude Code