Skip to content

Commit

Permalink
ast: Not allowing multi-value rules to have other rules in their extent
Browse files Browse the repository at this point in the history
Fixes: #5813
Signed-off-by: Johan Fylling <[email protected]>
  • Loading branch information
johanfylling authored and ashutosh-narkar committed Apr 24, 2023
1 parent 8e48167 commit 0be7f35
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 0 deletions.
13 changes: 13 additions & 0 deletions ast/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -873,6 +873,7 @@ func (c *Compiler) checkRuleConflicts() {
arities := make(map[int]struct{}, len(node.Values))
name := ""
var singleValueConflicts []Ref
var multiValueConflicts []Ref

for _, rule := range node.Values {
r := rule.(*Rule)
Expand Down Expand Up @@ -908,12 +909,24 @@ func (c *Compiler) checkRuleConflicts() {
singleValueConflicts = node.flattenChildren()
}
}

// Multi-value rules may not have any other rules in their extent; e.g.:
//
// data.p[v] { v := ... }
// data.p.q := 42 # In direct conflict with data.p[v], which is constructing a set and cannot have values assigned to a sub-path.

if r.Head.RuleKind() == MultiValue && len(node.Children) > 0 {
multiValueConflicts = node.flattenChildren()
}
}

switch {
case singleValueConflicts != nil:
c.err(NewError(TypeErr, node.Values[0].(*Rule).Loc(), "single-value rule %v conflicts with %v", name, singleValueConflicts))

case multiValueConflicts != nil:
c.err(NewError(TypeErr, node.Values[0].(*Rule).Loc(), "multi-value rule %v conflicts with %v", name, multiValueConflicts))

case len(kinds) > 1 || len(arities) > 1:
c.err(NewError(TypeErr, node.Values[0].(*Rule).Loc(), "conflicting rules %v found", name))

Expand Down
18 changes: 18 additions & 0 deletions ast/compile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1959,6 +1959,24 @@ func TestCompilerCheckRuleConflictsDotsInRuleHeads(t *testing.T) {
p.q.s = "x" { true }
`),
},
{
note: "multi-value rule with other rule overlap",
modules: modules(
`package pkg
p[v] { v := ["a", "b"][_] }
p.q := 42
`),
err: "rego_type_error: multi-value rule data.pkg.p conflicts with [data.pkg.p.q]",
},
{
note: "multi-value rule with other rule (ref) overlap",
modules: modules(
`package pkg
p[v] { v := ["a", "b"][_] }
p.q.r { true }
`),
err: "rego_type_error: multi-value rule data.pkg.p conflicts with [data.pkg.p.q.r]",
},
}
for _, tc := range tests {
t.Run(tc.note, func(t *testing.T) {
Expand Down

0 comments on commit 0be7f35

Please sign in to comment.