diff --git a/src/parse/query.rs b/src/parse/query.rs index 3061e943..41060761 100644 --- a/src/parse/query.rs +++ b/src/parse/query.rs @@ -198,8 +198,9 @@ pub(crate) fn parse_query( algo_impl.process_options(&mut options, span)?; let arity = algo_impl.arity(&options, &head, span)?; + ensure!(arity != 0, EmptyRowForConstRule(span)); ensure!( - arity == 0 || head.is_empty() || arity == head.len(), + head.is_empty() || arity == head.len(), FixedRuleHeadArityMismatch(arity, head.len(), span) ); progs.insert( @@ -764,6 +765,11 @@ fn parse_algo_rule( #[diagnostic(help("Expected arity: {0}, number of arguments given: {1}"))] struct FixedRuleHeadArityMismatch(usize, usize, #[label] SourceSpan); +#[derive(Debug, Error, Diagnostic)] +#[error("Encountered empty row for constant rule")] +#[diagnostic(code(parser::const_rule_empty_row))] +struct EmptyRowForConstRule(#[label] SourceSpan); + fn make_empty_const_rule(prog: &mut InputProgram, bindings: &[Symbol]) { let entry_symbol = Symbol::new(PROG_ENTRY, Default::default()); let mut options = BTreeMap::new(); diff --git a/tests/air_routes.rs b/tests/air_routes.rs index 5e45b78e..36f7354a 100644 --- a/tests/air_routes.rs +++ b/tests/air_routes.rs @@ -159,6 +159,18 @@ fn dfs() { dbg!(dfs.elapsed()); } +#[test] +fn empty() { + check_db(); + let res = TEST_DB.run_script( + r#" + ?[id, name] <- [[]] + "#, + &Default::default(), + ); + assert!(res.is_err()); +} + #[test] fn bfs() { check_db();