-
Notifications
You must be signed in to change notification settings - Fork 1.5k
ast: support naked refs in rule indexer #7897
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| if !ok { | ||
| count = 0 | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That seemed redundant. Let's embrace there zero value 😉
✅ Deploy Preview for openpolicyagent ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
v1/topdown/topdown_partial_test.go
Outdated
| q if { | ||
| __local6__2 = input | ||
| data.partial.test.mock_concat(["foo"], __local6__2, __local5__2) | ||
| __local4__2 = __local5__2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These partial tests previously had no RI action going in, because their "naked ref" function bodies weren't indexed. Now they are. This brings a small change in ordering somewhere, so that the numbers here change. But that should be OK.
|
Had a quick look at the failures, the typo is obvious. The other failure makes me think that there's something going on with unstable ordering, since it's only in one run of our many test suites. Will have another look when I'm back. |
philipaconrad
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for putting this PR together @srenatus! The changes look solid to me-- nothing too surprising, mostly small refactors + the new naked ref case for the rule indexer.
Assuming the test failures you mentioned earlier get resolved, I think this is good to merge. 🙂
| // (y=12) respectively. | ||
| func eqOperandsToRefAndValue(isVirtual func(Ref) bool, args []*Term, a, b *Term) (*refindex, bool) { | ||
| switch v := a.Value.(type) { | ||
| func eqOperandsToRefAndValue(isVirtual func(Ref) bool, args []*Term, a, b Value) (*refindex, bool) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[question]: I assume this and the other type changes from *Term -> Value were because we were just unwrapping the Terms with .Value inside the functions anyway, correct? This looks like it peels a layer of pointer indirection off, which might matter eventually elsewhere for performance. 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like your explanation and I should have given mine upfront: it allows passing in the anyValue fake var that drives the indexing of naked refs (without requiring a fake term wrapped around it).
82da14b to
f8e53ec
Compare
| if err != nil { | ||
| // Handle error. | ||
| } | ||
| makeStable(pqs.Queries) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm mildly annoyed by this -- I hope this change is not a boomerang that'll hit us in the back of our heads when we least expect it. But it shouldn't be, ordering of rules returned by the RI isn't guaranteed, so I haven't tracked down where this is coming from. We have a bunch of map iterations in the ast/index.go code, so it could be any (or all) of those.
| q if { __local6__2 = input data.partial.test.mock_concat(["foo"], __local6__2, __local5__2) __local4__2 = __local5__2 } | ||
| mock_concat(__local0__4, __local1__4) = ["foo", "bar"] if { input.foo = x_term_4_04 x_term_4_04 } | ||
| mock_concat(__local2__3, __local3__3) = ["bar", "baz"] if { input.bar = x_term_3_03 x_term_3_03 }`, | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The numbers changed slightly, but I also find the condensed version easier to compare. Below, where it was already condensed, the change is much more obvious. 👇
This turned out to be a low-hanging fruit. With this change, these two
expression behave the same as far as the rule indexer is concerned:
input.foo != false # this worked before
input.foo # now works, too!
Under the hood, expressions like `input.foo` are handled as if it was
written as `x = input.foo` for a synthetic variable. That way, it's
handled the same -- 100% the same, so we're not looking at the actual
value of `input.foo` in the rule index lookup, we're just selecting the
rules that use it (and omit the ones that don't). The actual FAIL that
may happen in evaluation if `input.foo` is `false` will just happen as
it always has, and give up on that subtree for evaluation.
Also similar to `input.foo != false`, there is no support with `not` or
`with` in the rule index.
Note that we don't handle function arguments in the same way:
If you have a function (with some more rule bodies so that RI matters),
```rego
foo(a, b) if {
a > 1
b == 200
}
```
and the evaluator does a lookup of `foo(2, 100)`, it will not evaluate
that body -- because `b` is used in the indexer with value `100`.
Now, if that was a naked expression,
```rego
foo(a, b) if {
a > 1
b
}
```
it will not be handled any different with this change: It's a function
argument, so it cannot be undefined. There's no point in using the rule
index to reference this function body for "b is defined" -- it always is
if we're calling the function.
Previously mentioned in open-policy-agent#642 (comment).
Signed-off-by: Stephan Renatus <[email protected]>
f8e53ec to
ffe5cfc
Compare
|
Merging, since @philipaconrad reviewed it and the test is now passing. |
This turned out to be a low-hanging fruit. With this change, these two expression behave the same as far as the rule indexer is concerned:
Under the hood, expressions like
input.fooare handled as if it was written asx = input.foofor a synthetic variable. That way, it's handled the same -- 100% the same, so we're not looking at the actual value ofinput.fooin the rule index lookup, we're just selecting the rules that use it (and omit the ones that don't). The actual FAIL that may happen in evaluation ifinput.fooisfalsewill just happen as it always has, and give up on that subtree for evaluation.Also similar to
input.foo != false, there is no support withnotorwithin the rule index.Note that we don't handle function arguments in the same way:
If you have a function (with some more rule bodies so that RI matters),
and the evaluator does a lookup of
foo(2, 100), it will not evaluate that body -- becausebis used in the indexer with value100.Now, if that was a naked expression,
it will not be handled any different with this change: It's a function argument, so it cannot be undefined. There's no point in using the rule index to reference this function body for "b is defined" -- it always is if we're calling the function.
Previously mentioned in #642 (comment).