Skip to content

Conversation

@rcosta358
Copy link
Collaborator

@rcosta358 rcosta358 commented Nov 5, 2025

Previously, we weren't checking if refinement predicates were actually boolean expressions, and this was only caught by the SMT solver.

Examples

Refinements

public class InvalidRefinement {
    void example() {
        @Refinement("_ + 1") // not a boolean expression
        int x = 5;
    }
}
Before
Found Error: class com.microsoft.z3.IntExpr cannot be cast to class com.microsoft.z3.BoolExpr (com.microsoft.z3.IntExpr and com.microsoft.z3.BoolExpr are in unnamed module of loader org.codehaus.mojo.exec.URLClassLoaderBuilder$ExecJavaClassLoader @7a729f84)
After
Found Error: Refinement predicate must be a boolean expression

Refinement Aliases

@RefinementAlias("Test(int v) { v }") // does not return a boolean expression
public class InvalidRefinementAlias {

    void example() {
        @Refinement("Test(_)")
        int x = 1;
    }
}
Before
Found Error: class com.microsoft.z3.IntExpr cannot be cast to class com.microsoft.z3.BoolExpr (com.microsoft.z3.IntExpr and com.microsoft.z3.BoolExpr are in unnamed module of loader org.codehaus.mojo.exec.URLClassLoaderBuilder$ExecJavaClassLoader @78d6447a)
After
Found Error: Refinement alias must return a boolean expression
State Refinements
public class InvalidStateRefinementFrom {

    @StateRefinement(from="123") // not a boolean expression
    void example() {}
}
Before:
class com.microsoft.z3.IntNum cannot be cast to class com.microsoft.z3.BoolExpr (com.microsoft.z3.IntNum and com.microsoft.z3.BoolExpr are in unnamed module of loader org.codehaus.mojo.exec.URLClassLoaderBuilder$ExecJavaClassLoader @38bb9d7a)
After
Found Error: State refinement transition must be a boolean expression

The same happens with state refinements in constructors and with to transitions.

@rcosta358 rcosta358 self-assigned this Nov 5, 2025
public boolean isBooleanExpression() {
if (this instanceof LiteralBoolean || this instanceof Ite || this instanceof AliasInvocation
|| this instanceof FunctionInvocation) {
return true;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We assume ghost and alias invocations always return boolean expressions.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but ghosts can be ints right? like size is that an issue?

Copy link
Collaborator Author

@rcosta358 rcosta358 Nov 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah in that case we can't catch it there since would need the context to check if it actually returns a boolean.

Copy link
Collaborator

@CatarinaGamboa CatarinaGamboa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. We should also have tests that check if the right error message is sent and not just if the verifier fails or not, I'll add a issue with that and we can discuss it later

@rcosta358 rcosta358 merged commit 1ca6aa2 into liquid-java:main Nov 8, 2025
1 check passed
@rcosta358 rcosta358 deleted the check-valid-refinement branch November 8, 2025 19:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants