|
| 1 | +--- |
| 2 | +title: Diagnostic Structure |
| 3 | +parent: Diagnostics |
| 4 | +nav_order: 4 |
| 5 | +--- |
| 6 | + |
| 7 | +# Diagnostic Structure |
| 8 | + |
| 9 | +Consider the following refinement error: |
| 10 | + |
| 11 | + |
| 12 | +{: .diagnostic-image } |
| 13 | + |
| 14 | +Each part gives a different piece of information: |
| 15 | + |
| 16 | +| Part | Meaning | |
| 17 | +| --- | --- | |
| 18 | +| `Refinement Error` | The kind of diagnostic being reported | |
| 19 | +| `#ret² == x / 2 && x > 0` | What LiquidJava knows at the return site. Here, the returned value is `x / 2`, and the parameter refinement says `x > 0` | |
| 20 | +| `is not a subtype of` | LiquidJava is checking whether the inferred refinement is strong enough to satisfy the declared one | |
| 21 | +| `#ret² > 0` | The declared return refinement, obtained from `@Refinement(value="_ > 0", ...)`. | |
| 22 | +| Source snippet | The surrounding lines help locate the failing code in context | |
| 23 | +| Caret line | The `^` marks the exact expression that caused the violation | |
| 24 | +| `result must be positive` | The custom error message from the annotation's `msg` parameter | |
| 25 | +| `Counterexample: x == 1 && #ret² == 0` | A concrete model showing why the check fails. Here we can see the failure arises because if `x == 1`, then `x / 2 == 0` | |
| 26 | + |
| 27 | +## Understanding the Counterexample |
| 28 | + |
| 29 | +The counterexample is a concrete assignment of values that makes the verification fail. |
| 30 | + |
| 31 | +In the example above: |
| 32 | +- `x == 1` satisfies the parameter refinement `x > 0` |
| 33 | +- `#ret² == 0` follows from the return expression `x / 2`, since integer division makes `1 / 2 == 0` |
| 34 | +- `0 > 0` is false, so the declared return refinement is violated |
| 35 | + |
| 36 | +So the counterexample explains exactly why LiquidJava cannot prove that `x / 2` is always positive even when `x > 0`. To fix this error, we would need to either change the return expression to allow to return zero with the refinement `_ >= 0`, or strengthen the parameter refinement to require `x > 1`. |
| 37 | + |
| 38 | +## Internal Instance Variables |
| 39 | + |
| 40 | +Names such as `#ret²` are internal variables introduced by LiquidJava during verification. The small superscript number is a counter used to keep those generated variables unique. |
| 41 | + |
| 42 | +LiquidJava converts expressions into an internal A-normal form (ANF) before verification. Every time it creates a fresh internal variable during that process, the counter is incremented. This is why you may see names such as `#ret²` in the diagnostics. |
| 43 | + |
| 44 | +In practice, you can read `#ret²` as "the internal variable that represents this return value occurrence". |
| 45 | + |
| 46 | +```java |
| 47 | +int example(int x) { // x⁰ |
| 48 | + x = x + 1; // x¹ == x⁰ + 1 |
| 49 | + int y = x / 2; // y² == x¹ / 2 |
| 50 | + return y; // #ret³ == y² |
| 51 | +} |
| 52 | +``` |
0 commit comments