Problem
QueryExpr::BinaryOp { lhs: Box<QueryExpr>, rhs: Box<QueryExpr>, .. } requires both sides to be full vector subqueries. There is no way to express a scalar/literal operand. PromQL routinely combines a vector with a bare number — threshold alerts (v > 10*1024*1024), unit conversions (rate(m[5m]) * 100) — and none of these lower today.
L3Expr (used inside Filter/Project/Sort) already has a Literal variant and handles this fine at the scalar-expression level. The gap is specific to the relational-level QueryExpr::BinaryOp node. The PromQL front end's walk() dispatcher has no case for a bare Expr::NumberLiteral/Expr::StringLiteral at the position a BinaryOp operand recurses into — it explicitly rejects them ("bare scalar/string at top level"), so walk(&bin.rhs) errors whenever rhs is a literal.
Reproduction
crates/lower/tests/promql_conformance.rs, test scalar_literal_operand_is_rejected__GAP:
#[test]
fn scalar_literal_operand_is_rejected__GAP() {
// SEMANTICS (PromQL): `v > 10*1024*1024` filters by a scalar threshold.
// We have no scalar/number-literal expression in L2, so a literal operand
// is rejected. Common real-world thresholds therefore don't lower yet.
let _ = rejected("node_filesystem_avail_bytes > 10*1024*1024");
}
This test currently asserts the rejection (documents the gap). Flipping it to assert a successful lowering is the acceptance criterion.
Problem
QueryExpr::BinaryOp { lhs: Box<QueryExpr>, rhs: Box<QueryExpr>, .. }requires both sides to be full vector subqueries. There is no way to express a scalar/literal operand. PromQL routinely combines a vector with a bare number — threshold alerts (v > 10*1024*1024), unit conversions (rate(m[5m]) * 100) — and none of these lower today.L3Expr(used insideFilter/Project/Sort) already has aLiteralvariant and handles this fine at the scalar-expression level. The gap is specific to the relational-levelQueryExpr::BinaryOpnode. The PromQL front end'swalk()dispatcher has no case for a bareExpr::NumberLiteral/Expr::StringLiteralat the position aBinaryOpoperand recurses into — it explicitly rejects them ("bare scalar/string at top level"), sowalk(&bin.rhs)errors wheneverrhsis a literal.Reproduction
crates/lower/tests/promql_conformance.rs, testscalar_literal_operand_is_rejected__GAP:This test currently asserts the rejection (documents the gap). Flipping it to assert a successful lowering is the acceptance criterion.