During partial evaluation, the equality operators discard unknown operands and return a concrete result. Specifically an expression like false || x == 'foo' with x unknown returns concrete false when using partial eval, claiming the expression is false for every possible value of x, which is not true. All other operatorsI tested (>, >=, in, &&/|| absorption comprehensions, function dispatch) propagate unknowns correctly.
Reproducing (I tested with 0.6.0):
import java.util.Map;
import org.projectnessie.cel.Env;
import org.projectnessie.cel.EnvOption;
import org.projectnessie.cel.EvalOption;
import org.projectnessie.cel.Program;
import org.projectnessie.cel.ProgramOption;
import org.projectnessie.cel.checker.Decls;
import org.projectnessie.cel.common.types.ref.Val;
import org.projectnessie.cel.interpreter.Activation;
import org.projectnessie.cel.interpreter.AttributePattern;
public class Repro {
static Env env;
static Val partialEval(String expr) {
Env.AstIssuesTuple parsed = env.parse(expr);
if (parsed.hasIssues()) throw new IllegalStateException(parsed.getIssues().toString());
Env.AstIssuesTuple checked = env.check(parsed.getAst());
if (checked.hasIssues()) throw new IllegalStateException(checked.getIssues().toString());
Program prg =
env.program(checked.getAst(), ProgramOption.evalOptions(EvalOption.OptPartialEval));
Activation.PartialActivation vars =
Activation.newPartialActivation(
Map.of(),
AttributePattern.newAttributePattern("x"),
AttributePattern.newAttributePattern("y"));
return prg.eval(vars).getVal();
}
public static void main(String[] args) {
env =
Env.newEnv(
EnvOption.declarations(
Decls.newVar("x", Decls.String), Decls.newVar("y", Decls.Int)));
System.out.println("x == 'foo' -> " + partialEval("x == 'foo'"));
System.out.println("x != 'foo' -> " + partialEval("x != 'foo'"));
System.out.println("y > 5 -> " + partialEval("y > 5"));
System.out.println("y >= 5 -> " + partialEval("y >= 5"));
System.out.println("x in ['foo'] -> " + partialEval("x in ['foo']"));
System.out.println("false || x == 'foo' -> " + partialEval("false || x == 'foo'"));
}
}
Output with both x and y unknown:
x == 'foo' -> bool{false} // expected: unknown{...}
x != 'foo' -> bool{true} // expected: unknown{...}
y > 5 -> unknown{1} // correct
y >= 5 -> unknown{1} // correct
x in ['foo'] -> unknown{1} // correct
false || x == 'foo' -> bool{false} // expected: unknown{...}
The fix doesn't seem too bad, I'm happy to put in a PR, but I wanted to check that I'm not missing something.
During partial evaluation, the equality operators discard unknown operands and return a concrete result. Specifically an expression like false || x == 'foo' with x unknown returns concrete false when using partial eval, claiming the expression is false for every possible value of x, which is not true. All other operatorsI tested (>, >=, in, &&/|| absorption comprehensions, function dispatch) propagate unknowns correctly.
Reproducing (I tested with 0.6.0):
Output with both x and y unknown:
The fix doesn't seem too bad, I'm happy to put in a PR, but I wanted to check that I'm not missing something.