Skip to content

Commit 1f44432

Browse files
committed
Improve Error Message
1 parent 2f5f90e commit 1f44432

4 files changed

Lines changed: 63 additions & 5 deletions

File tree

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package testSuite;
2+
3+
import liquidjava.specification.Ghost;
4+
import liquidjava.specification.StateRefinement;
5+
6+
@Ghost("int amount")
7+
public class ErrorSMTUnknownState {
8+
@StateRefinement(to = "amount(this) > 0")
9+
public ErrorSMTUnknownState() {}
10+
11+
@StateRefinement(from = "amount(this) < limit")
12+
public void consume(int limit) {}
13+
14+
public static void test(double limit) {
15+
ErrorSMTUnknownState value = new ErrorSMTUnknownState();
16+
int boundary = (int) limit;
17+
value.consume(boundary); // Expect: SMT Unknown Error
18+
}
19+
}
Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,28 @@
11
package liquidjava.diagnostics.errors;
22

3+
import spoon.reflect.cu.SourcePosition;
4+
35
/**
46
* Error indicating that the SMT solver could not decide a verification condition
57
*/
68
public class SMTUnknownError extends LJError {
9+
private SourcePosition declarationPosition;
710

811
public SMTUnknownError(String reason) {
9-
super("SMT Unknown Error",
10-
"The SMT solver returned UNKNOWN and could not verify the refinement. Reason: " + reason, null, null);
12+
super("SMT Unknown Error", "The SMT solver could not prove refinement", null, null);
13+
String tacticFailure = "smt tactic failed to show goal to be sat/unsat ";
14+
if (reason.startsWith(tacticFailure)) {
15+
reason = reason.substring(tacticFailure.length()).replace("(", "").replace(")", "");
16+
}
17+
setHint("Reason: " + reason);
18+
}
19+
20+
public void setDeclarationPosition(SourcePosition declarationPosition) {
21+
this.declarationPosition = declarationPosition;
22+
}
23+
24+
@Override
25+
public SourcePosition getDeclarationPosition() {
26+
return declarationPosition;
1127
}
1228
}

‎liquidjava-verifier/src/main/java/liquidjava/processor/refinement_checker/VCChecker.java‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ public void processSubtyping(Predicate expectedType, List<GhostState> list, CtEl
7070
SMTResult result;
7171
try {
7272
result = dischargeToSMT(expected, premises, annotationValuePos, true);
73+
} catch (SMTUnknownError error) {
74+
error.setDeclarationPosition(declarationPosition);
75+
DebugLog.smtError(error.getMessage());
76+
throw error;
7377
} catch (RuntimeException ex) {
7478
DebugLog.smtError(ex.getMessage());
7579
throw ex;
@@ -94,7 +98,13 @@ public void processSubtyping(Predicate expectedType, List<GhostState> list, CtEl
9498
*/
9599
public void processSubtyping(Predicate type, Predicate expectedType, List<GhostState> list, CtElement element,
96100
SourcePosition declarationPosition, Factory f) throws LJError {
97-
SMTResult result = verifySMTSubtypeStates(type, expectedType, list, element.getPosition(), f);
101+
SMTResult result;
102+
try {
103+
result = verifySMTSubtypeStates(type, expectedType, list, element.getPosition(), f);
104+
} catch (SMTUnknownError error) {
105+
error.setDeclarationPosition(declarationPosition);
106+
throw error;
107+
}
98108
if (result.isError())
99109
throwRefinementError(element.getPosition(), declarationPosition, expectedType, type,
100110
result.getCounterexample(), null);

‎liquidjava-verifier/src/main/java/liquidjava/processor/refinement_checker/object_checkers/AuxStateHandler.java‎

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import liquidjava.diagnostics.errors.IllegalConstructorTransitionError;
88
import liquidjava.diagnostics.errors.InvalidRefinementError;
99
import liquidjava.diagnostics.errors.LJError;
10+
import liquidjava.diagnostics.errors.SMTUnknownError;
1011
import liquidjava.processor.context.*;
1112
import liquidjava.processor.refinement_checker.TypeChecker;
1213
import liquidjava.processor.refinement_checker.TypeCheckingUtils;
@@ -430,7 +431,14 @@ public static void updateGhostField(CtFieldWrite<?> fw, TypeChecker tc) throws L
430431
Predicate expectState = stateChange.getFrom().substituteVariable(Keys.THIS, instanceName)
431432
.changeOldMentions(vi.getName(), instanceName);
432433

433-
if (!tc.checkStateSMT(prevState, expectState, fw.getPosition())) { // Invalid field transition
434+
boolean validTransition;
435+
try {
436+
validTransition = tc.checkStateSMT(prevState, expectState, fw.getPosition());
437+
} catch (SMTUnknownError error) {
438+
error.setDeclarationPosition(field.getDeclaringType().getPosition());
439+
throw error;
440+
}
441+
if (!validTransition) { // Invalid field transition
434442
tc.throwStateRefinementError(fw.getPosition(), field.getDeclaringType().getPosition(), prevState,
435443
expectState, stateChange.getMessage());
436444
return;
@@ -496,7 +504,12 @@ private static void changeState(TypeChecker tc, VariableInstance vi, RefinedFunc
496504
}
497505
expectState = expectState.changeOldMentions(vi.getName(), instanceName);
498506

499-
found = tc.checkStateSMT(prevCheck, expectState, invocation.getPosition());
507+
try {
508+
found = tc.checkStateSMT(prevCheck, expectState, invocation.getPosition());
509+
} catch (SMTUnknownError error) {
510+
error.setDeclarationPosition(stateChange.getFromPosition());
511+
throw error;
512+
}
500513
if (found && stateChange.hasTo()) {
501514
String newInstanceName = String.format(Formats.INSTANCE, name, tc.getContext().getCounter());
502515
// Non-void: `_` is the return value; void: legacy alias for the new instance.

0 commit comments

Comments
 (0)