@@ -86,6 +86,8 @@ static List<String> returnedValues(RefinementError error, Context context) {
8686 if (declared == null || !declared .isValidPosition () || declared .getFile () == null )
8787 continue ;
8888 Expression guaranteed = withoutGhostDefinitions (call .returned ().getExpression (), variable , error , context );
89+ if (!namesOnlyCodeVariables (guaranteed , context ))
90+ continue ;
8991 String value = ExpressionFormatter .format (new Var (variable ), error .getDisplayNames ());
9092 String says = isTrue (guaranteed ) ? "guarantees nothing about " + value
9193 : "guarantees only " + ExpressionFormatter .format (
@@ -132,6 +134,20 @@ private static boolean isGhost(String name, Context context) {
132134 || context .getGhostStates ().stream ().anyMatch (g -> g .getParent () == null && g .matches (name )));
133135 }
134136
137+ /**
138+ * Whether every variable of the refinement but the value is one the code names: an argument the verifier names
139+ * after the callee's parameter, such as the {@code 0} of {@code twice(0)} for {@code _ == b * 2}, would read as
140+ * that parameter
141+ */
142+ private static boolean namesOnlyCodeVariables (Expression refinement , Context context ) {
143+ List <String > variables = new ArrayList <>();
144+ refinement .getVariableNames (variables );
145+ return variables .stream ().filter (name -> !Keys .WILDCARD .equals (name ))
146+ .allMatch (name -> context .getVariableByName (name ) instanceof Variable
147+ || context .getVariableByName (name )instanceof VariableInstance instance
148+ && context .getVariableFromInstance (instance ) != null );
149+ }
150+
135151 /** Whether {@code fact} is {@code variable == ghost}, the argument's own definition */
136152 private static boolean definesGhostAs (Expression fact , Expression ghost , String variable ) {
137153 return fact instanceof BinaryExpression equality && "==" .equals (equality .getOperator ())
0 commit comments