Skip to content

Commit 91e2958

Browse files
committed
Add Diagnostic Sections
1 parent 0ca443f commit 91e2958

7 files changed

Lines changed: 156 additions & 0 deletions

File tree

‎_sass/custom/custom.scss‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,18 @@
4545
box-shadow: 0 18px 36px rgba(15, 23, 42, 0.18);
4646
}
4747

48+
.main-content .diagnostic-image {
49+
display: block;
50+
width: 100%;
51+
max-width: 100%;
52+
margin: 1rem 0 1.5rem;
53+
overflow: hidden;
54+
border: 1px solid rgba(38, 48, 68, 0.45);
55+
border-radius: 1rem;
56+
background: linear-gradient(180deg, #172033 0%, #111827 100%);
57+
box-shadow: 0 18px 36px rgba(15, 23, 42, 0.18);
58+
}
59+
4860
.main-content pre,
4961
.main-content pre.highlight code,
5062
.main-content div.highlighter-rouge pre,

‎assets/images/error-message.png‎

128 KB
Loading

‎diagnostics/custom-messages.md‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
title: Custom Messages
3+
parent: Diagnostics
4+
nav_order: 3
5+
---
6+
7+
# Custom Messages
8+
9+
A custom message can be provided to any `@Refinement` or `@StateRefinement` annotation using the `msg` parameter. This message will be included in the diagnostic when a violation of that annotation is reported, to provide a clearer explanation of the API rule that was violated.
10+
11+
```java
12+
import liquidjava.specification.*;
13+
14+
@StateSet({"open", "closed"})
15+
public class MyFile {
16+
@StateRefinement(to="open()")
17+
public MyFile() {}
18+
19+
@StateRefinement(from="open()", msg="file must be open to read")
20+
public void read(@Refinement(value="_ > 0", msg="bytes must be greater than zero") int bytes) {}
21+
22+
@StateRefinement(from="open()", to="closed()", msg="file must be open to close")
23+
public void close() {}
24+
}
25+
```
26+
27+
This is useful to explain the API rule in domain terms for users to quickly understand what went wrong.

‎diagnostics/errors.md‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
title: Errors
3+
parent: Diagnostics
4+
nav_order: 1
5+
---
6+
7+
# Errors
8+
9+
An error can be caused by a refinement violation, an invalid refinement, or another particular issue.
10+
11+
| Error | Meaning |
12+
| --- | --- |
13+
| `RefinementError` | A refinement was violated |
14+
| `StateRefinementError` | A state refinement was violated |
15+
| `NotFoundError` | An element used in a refinement could not be found |
16+
| `SyntaxError` | The syntax used in a refinement is invalid |
17+
| `ArgumentMismatchError` | A ghost or state invocation has the wrong number or type of arguments |
18+
| `StateConflictError` | A state refinement becomes unsatisfiable because it combines disjoint states |
19+
| `IllegalConstructorTransitionError` | A constructor state refinement declares an illegal `from` transition |
20+
| `InvalidRefinementError` | A refinement is semantically invalid, such as a non-boolean expression |
21+
| `CustomError` | Any other error, such as providing a non-existent path to verify |
22+
23+
LiquidJava is only able to report **at most one error per method** to avoid cascading failures. If there are multiple errors in a method, the verifier will report the first one it encounters, and stop verifying the rest of the method, meaning that fixing one error can sometimes reveal another that was previously hidden.

‎diagnostics/index.md‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
title: Diagnostics
3+
nav_order: 3
4+
has_children: true
5+
has_toc: false
6+
permalink: /diagnostics/
7+
description: Understand LiquidJava errors, warnings, diagnostic structure, and custom diagnostic messages.
8+
cards:
9+
- title: Errors
10+
url: /diagnostics/errors/
11+
description: Learn about the different verification errors LiquidJava can report and what each one means.
12+
- title: Warnings
13+
url: /diagnostics/warnings/
14+
description: Learn about the different verification warnings LiquidJava can report and what each one means.
15+
- title: Structure
16+
url: /diagnostics/structure/
17+
description: Learn how to understand a diagnostic message.
18+
- title: Custom Messages
19+
url: /diagnostics/custom-messages/
20+
description: Learn how to provide clearer diagnostic messages using the `msg` parameter.
21+
---
22+
23+
# Diagnostics
24+
25+
Learn how to understand LiquidJava diagnostics, from verification errors and warnings to the structure of a full diagnostic message.
26+
27+
{% include card_grid.html cards=page.cards %}

‎diagnostics/structure.md‎

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
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+
![Example LiquidJava refinement error]({{ '/assets/images/error-message.png' | relative_url }})
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+
```

‎diagnostics/warnings.md‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
title: Warnings
3+
parent: Diagnostics
4+
nav_order: 2
5+
---
6+
7+
# Warnings
8+
9+
Warnings do not affect the verification like errors, but they indicate that there is an issue that should probably be addressed.
10+
11+
| Warning | Meaning |
12+
| --- | --- |
13+
| `ExternalClassNotFoundWarning` | A class referenced by an external refinement cannot be found |
14+
| `ExternalMethodNotFoundWarning` | A method referenced by an external refinement cannot be found in the target class |
15+
| `CustomWarning` | Any other warning, such as reporting that Java compilation errors are present in the program |

0 commit comments

Comments
 (0)