JavaToLaurel: support null / reference-constant comparisons and values - #460
JavaToLaurel: support null / reference-constant comparisons and values#460tautschnig wants to merge 1 commit into
null / reference-constant comparisons and values#460Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the Java→Laurel front-end to support Java null in reference contexts by introducing a per-reference-sort distinguished null value (<sort>$null) and using that value for == null / != null comparisons and for standalone null where a target type is known. This prevents translation from crashing on BOT-typed null literals and adds a regression test covering the new behavior.
Changes:
- Emit a per-composite-sort uninterpreted null constant function (
<sort>$null) and lower reference== null/!= nullto equality against it. - Add “nullable” conversion in specific typed contexts (return, local init, assignment, call-arg) so standalone
nullpicks up the expected reference sort. - Add
NullReferenceTestto verifynullcomparisons and typednullvalues translate and verify successfully.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| verifier/src/main/java/org/strata/jverify/verifier/compiler/generator/laurel/JavaToLaurelCompiler.java | Adds per-sort null modeling, typed-null conversion helpers, and special-casing for == null / != null. |
| verifier/src/test/java/org/strata/jverify/verifier/tests/javasupport/NullReferenceTest.java | New regression test exercising reference comparisons and typed standalone null uses. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
4b2b4be to
b4667e4
Compare
|
CI is red because this bumps the |
|
This is a partial solution right? I don't know by heart but I imagine there are quite some cases that it doesn't handle. For example, it can't prove that a fresh object is not The solution I had in mind for supporting nullable types was on the Laurel side, but it will take quite a bit more time to implement it. Could we add comments to the code added in this PR to indicate that this solution is a stop-gap until Laurel has better support for this? The Laurel support I have in mind is to support "implicit conversions" that allow Laurel to insert conversions to translate between types ( On top of that, we could even added dedicated Nullable support to Laurel, adding a |
|
+1 on the Laurel plan and the stop-gap comment. One thing worth pinning beyond "temporary": Minor: no negative test — a should-fail case ( |
Object references translate to opaque Laurel `compositeType` sorts with no built-in null, so any use of the `null` literal (Java's BOT-typed null) hit `convertConstantValue`'s default and crashed translation with "Unsupported constant type tag: BOT" — methods involving `null` or reference comparisons could not be emitted or verified. Model null per reference sort: alongside each opaque composite sort `S`, declare an uninterpreted 0-arg function `S$null : S` — a distinguished, otherwise unconstrained element of the sort. Then: - `x == null` / `x != null` on an object reference lower to `eq(x, S$null)` / `neq(x, S$null)`; on an array (never null in the map model) they fold to a boolean; `null == null` folds. - Standalone `null` values take their reference sort from the use-site expected type: `return null;` (return type), `T a = null;` (declared local type), `a = null;` (assignment target), `foo(null)` (callee parameter type). `S$null` is uninterpreted, so this soundly models reference (in)equality with null without committing to a concrete identity. Helpers: `nullRefForType` (the `S$null` value), `isNullLiteral` (peels parens/casts so `(T) null` is recognised), `convertNullable`. Contexts with no known target type (ternary branches, array-element null) still reject a bare null, now with a clear diagnostic. Adds NullReferenceTest (comparison + return/local/assignment/call-arg null, all verify). Front-end only; no Strata submodule change. Per review feedback (keyboardDrummer, fabiomadge): this per-sort null encoding is a stop-gap until Laurel gains first-class nullable support (a shared `Null` value + `Nullable<T>` with implicit conversions). The `NULL_REF_SUFFIX` doc records that plan, and a note at the `S$null` emission site records the soundness assumption it relies on — per-sort nulls are sound only while composite sorts carry no subtyping, so a value of one sort is never compared against another sort's null; if upcasting between composite sorts becomes expressible this would turn unsound, motivating the eventual single shared `Null`. Adds NullReferenceLimitationsTest pinning the deliberate limitations as should-fail: an unconstrained reference is proved neither null nor non-null, and a freshly allocated object is not provably non-null. Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
b4667e4 to
fe020b3
Compare
|
@fabiomadge Strata pin is back to main’s |
|
@keyboardDrummer Agreed it’s a stop-gap — marked as such in the |
| * Not over-permissive: an unconstrained reference cannot be proved | ||
| * non-null — it may be the sort's {@code $null} element. | ||
| */ | ||
| static void cannotProveParamNonNull(Object o) { |
There was a problem hiding this comment.
Just a FYI: the design of JVerify is to assume that all reference variables are non-null, unless annotated with @Nullable.
Object references translate to opaque Laurel
compositeTypesorts with no built-in null, so any use of thenullliteral (Java's BOT-typed null) hitconvertConstantValue's default and crashed translation with "Unsupported constant type tag: BOT" — methods involvingnullor reference comparisons could not be emitted or verified.Model null per reference sort: alongside each opaque composite sort
S, declare an uninterpreted 0-arg functionS$null : S— a distinguished, otherwise unconstrained element of the sort. Then:x == null/x != nullon an object reference lower toeq(x, S$null)/neq(x, S$null); on an array (never null in the map model) they fold to a boolean;null == nullfolds.nullvalues take their reference sort from the use-site expected type:return null;(return type),T a = null;(declared local type),a = null;(assignment target),foo(null)(callee parameter type).S$nullis uninterpreted, so this soundly models reference (in)equality with null without committing to a concrete identity. Helpers:nullRefForType(theS$nullvalue),isNullLiteral(peels parens/casts so(T) nullis recognised),convertNullable. Contexts with no known target type (ternary branches, array-element null) still reject a bare null, now with a clear diagnostic.Adds NullReferenceTest (comparison + return/local/assignment/call-arg null, all verify). Front-end only; no Strata submodule change.
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0.