build(deps): bump github.com/open-policy-agent/opa from 1.8.0 to 1.9.0
Bumps [github.com/open-policy-agent/opa](https://github.com/open-policy-agent/opa) from 1.8.0 to 1.9.0. - [Release notes](https://github.com/open-policy-agent/opa/releases) - [Changelog](https://github.com/open-policy-agent/opa/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-policy-agent/opa/compare/v1.8.0...v1.9.0) --- updated-dependencies: - dependency-name: github.com/open-policy-agent/opa dependency-version: 1.9.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
committed by
Ralf Haferkamp
parent
703b8dd084
commit
d1ebbde760
+4867
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -176,7 +176,7 @@ func LoadPathsForRegoVersion(regoVersion ast.RegoVersion,
|
||||
}
|
||||
}
|
||||
|
||||
if len(nonBundlePaths) == 0 {
|
||||
if asBundle {
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
|
||||
+50
@@ -34,6 +34,7 @@ type (
|
||||
RelatedResources []*RelatedResourceAnnotation `json:"related_resources,omitempty"`
|
||||
Authors []*AuthorAnnotation `json:"authors,omitempty"`
|
||||
Schemas []*SchemaAnnotation `json:"schemas,omitempty"`
|
||||
Compile *CompileAnnotation `json:"compile,omitempty"`
|
||||
Custom map[string]any `json:"custom,omitempty"`
|
||||
Location *Location `json:"location,omitempty"`
|
||||
|
||||
@@ -48,6 +49,11 @@ type (
|
||||
Definition *any `json:"definition,omitempty"`
|
||||
}
|
||||
|
||||
CompileAnnotation struct {
|
||||
Unknowns []Ref `json:"unknowns,omitempty"`
|
||||
MaskRule Ref `json:"mask_rule,omitempty"` // NOTE: This doesn't need to start with "data.package", it can be relative
|
||||
}
|
||||
|
||||
AuthorAnnotation struct {
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email,omitempty"`
|
||||
@@ -151,6 +157,10 @@ func (a *Annotations) Compare(other *Annotations) int {
|
||||
return cmp
|
||||
}
|
||||
|
||||
if cmp := a.Compile.Compare(other.Compile); cmp != 0 {
|
||||
return cmp
|
||||
}
|
||||
|
||||
if a.Entrypoint != other.Entrypoint {
|
||||
if a.Entrypoint {
|
||||
return 1
|
||||
@@ -403,6 +413,8 @@ func (a *Annotations) Copy(node Node) *Annotations {
|
||||
cpy.Schemas[i] = a.Schemas[i].Copy()
|
||||
}
|
||||
|
||||
cpy.Compile = a.Compile.Copy()
|
||||
|
||||
if a.Custom != nil {
|
||||
cpy.Custom = deepcopy.Map(a.Custom)
|
||||
}
|
||||
@@ -716,6 +728,44 @@ func (s *SchemaAnnotation) String() string {
|
||||
return string(bs)
|
||||
}
|
||||
|
||||
// Copy returns a deep copy of s.
|
||||
func (c *CompileAnnotation) Copy() *CompileAnnotation {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
cpy := *c
|
||||
for i := range c.Unknowns {
|
||||
cpy.Unknowns[i] = c.Unknowns[i].Copy()
|
||||
}
|
||||
return &cpy
|
||||
}
|
||||
|
||||
// Compare returns an integer indicating if s is less than, equal to, or greater
|
||||
// than other.
|
||||
func (c *CompileAnnotation) Compare(other *CompileAnnotation) int {
|
||||
switch {
|
||||
case c == nil && other == nil:
|
||||
return 0
|
||||
case c != nil && other == nil:
|
||||
return 1
|
||||
case c == nil && other != nil:
|
||||
return -1
|
||||
}
|
||||
|
||||
if cmp := slices.CompareFunc(c.Unknowns, other.Unknowns,
|
||||
func(x, y Ref) int {
|
||||
return x.Compare(y)
|
||||
}); cmp != 0 {
|
||||
return cmp
|
||||
}
|
||||
return c.MaskRule.Compare(other.MaskRule)
|
||||
}
|
||||
|
||||
func (c *CompileAnnotation) String() string {
|
||||
bs, _ := json.Marshal(c)
|
||||
return string(bs)
|
||||
}
|
||||
|
||||
func newAnnotationSet() *AnnotationSet {
|
||||
return &AnnotationSet{
|
||||
byRule: map[*Rule][]*Annotations{},
|
||||
|
||||
+34
-22
@@ -213,7 +213,7 @@ func (i *baseDocEqIndex) Lookup(resolver ValueResolver) (*IndexResult, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (i *baseDocEqIndex) AllRules(_ ValueResolver) (*IndexResult, error) {
|
||||
func (i *baseDocEqIndex) AllRules(ValueResolver) (*IndexResult, error) {
|
||||
tr := newTrieTraversalResult()
|
||||
|
||||
// Walk over the rule trie and accumulate _all_ rules
|
||||
@@ -285,33 +285,51 @@ func newrefindices(isVirtual func(Ref) bool) *refindices {
|
||||
}
|
||||
}
|
||||
|
||||
// anyValue is a fake variable we used to put "naked ref" expressions
|
||||
// into the rule index
|
||||
var anyValue = Var("__any__")
|
||||
|
||||
// Update attempts to update the refindices for the given expression in the
|
||||
// given rule. If the expression cannot be indexed the update does not affect
|
||||
// the indices.
|
||||
func (i *refindices) Update(rule *Rule, expr *Expr) {
|
||||
|
||||
if expr.Negated {
|
||||
return
|
||||
}
|
||||
|
||||
if len(expr.With) > 0 {
|
||||
// NOTE(tsandall): In the future, we may need to consider expressions
|
||||
// that have with statements applied to them.
|
||||
return
|
||||
}
|
||||
|
||||
op := expr.Operator()
|
||||
if expr.Negated {
|
||||
// NOTE(sr): We could try to cover simple expressions, like
|
||||
// not input.funky => input.funky == false or undefined (two refindex?)
|
||||
return
|
||||
}
|
||||
|
||||
op := expr.Operator()
|
||||
if op == nil {
|
||||
if ts, ok := expr.Terms.(*Term); ok {
|
||||
// NOTE(sr): If we wanted to cover function args, we'd need to also
|
||||
// check for type "Var" here. But since it's impossible to call a
|
||||
// function with a undefined argument, there's no point to recording
|
||||
// "needs to be anything" for function args
|
||||
if ref, ok := ts.Value.(Ref); ok { // "naked ref"
|
||||
i.updateEq(rule, ref, anyValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a, b := expr.Operand(0), expr.Operand(1)
|
||||
switch {
|
||||
case op.Equal(equalityRef):
|
||||
i.updateEq(rule, expr)
|
||||
i.updateEq(rule, a.Value, b.Value)
|
||||
|
||||
case op.Equal(equalRef) && len(expr.Operands()) == 2:
|
||||
// NOTE(tsandall): if equal() is called with more than two arguments the
|
||||
// output value is being captured in which case the indexer cannot
|
||||
// exclude the rule if the equal() call would return false (because the
|
||||
// false value must still be produced.)
|
||||
i.updateEq(rule, expr)
|
||||
i.updateEq(rule, a.Value, b.Value)
|
||||
|
||||
case op.Equal(globMatchRef) && len(expr.Operands()) == 3:
|
||||
// NOTE(sr): Same as with equal() above -- 4 operands means the output
|
||||
@@ -366,8 +384,7 @@ func (i *refindices) Mapper(rule *Rule, ref Ref) *valueMapper {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *refindices) updateEq(rule *Rule, expr *Expr) {
|
||||
a, b := expr.Operand(0), expr.Operand(1)
|
||||
func (i *refindices) updateEq(rule *Rule, a, b Value) {
|
||||
args := rule.Head.Args
|
||||
if idx, ok := eqOperandsToRefAndValue(i.isVirtual, args, a, b); ok {
|
||||
i.insert(rule, idx)
|
||||
@@ -426,12 +443,7 @@ func (i *refindices) updateGlobMatch(rule *Rule, expr *Expr) {
|
||||
}
|
||||
|
||||
func (i *refindices) insert(rule *Rule, index *refindex) {
|
||||
|
||||
count, ok := i.frequency.Get(index.Ref)
|
||||
if !ok {
|
||||
count = 0
|
||||
}
|
||||
|
||||
count, _ := i.frequency.Get(index.Ref)
|
||||
i.frequency.Put(index.Ref, count+1)
|
||||
|
||||
for pos, other := range i.rules[rule] {
|
||||
@@ -454,7 +466,7 @@ func (i *refindices) index(rule *Rule, ref Ref) *refindex {
|
||||
}
|
||||
|
||||
type trieWalker interface {
|
||||
Do(x any) trieWalker
|
||||
Do(any) trieWalker
|
||||
}
|
||||
|
||||
type trieTraversalResult struct {
|
||||
@@ -816,11 +828,11 @@ func (node *trieNode) traverseUnknown(resolver ValueResolver, tr *trieTraversalR
|
||||
// for the argument number. So for `f(x, y) { x = 10; y = 12 }`, we'll
|
||||
// bind `args[0]` and `args[1]` to this rule when called for (x=10) and
|
||||
// (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) {
|
||||
switch v := a.(type) {
|
||||
case Var:
|
||||
for i, arg := range args {
|
||||
if arg.Value.Compare(a.Value) == 0 {
|
||||
if arg.Value.Compare(a) == 0 {
|
||||
if bval, ok := indexValue(b); ok {
|
||||
return &refindex{Ref: Ref{FunctionArgRootDocument, InternedTerm(i)}, Value: bval}, true
|
||||
}
|
||||
@@ -843,8 +855,8 @@ func eqOperandsToRefAndValue(isVirtual func(Ref) bool, args []*Term, a, b *Term)
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func indexValue(b *Term) (Value, bool) {
|
||||
switch b := b.Value.(type) {
|
||||
func indexValue(b Value) (Value, bool) {
|
||||
switch b := b.(type) {
|
||||
case Null, Boolean, Number, String, Var:
|
||||
return b, true
|
||||
case *Array:
|
||||
|
||||
+73
-29
@@ -1259,23 +1259,25 @@ func (p *Parser) parseLiteralExpr(negated bool) *Expr {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
// If we find a plain `every` identifier, attempt to parse an every expression,
|
||||
// add hint if it succeeds.
|
||||
if term, ok := expr.Terms.(*Term); ok && Var("every").Equal(term.Value) {
|
||||
var hint bool
|
||||
t := p.save()
|
||||
p.restore(s)
|
||||
if expr := p.futureParser().parseEvery(); expr != nil {
|
||||
_, hint = expr.Terms.(*Every)
|
||||
}
|
||||
p.restore(t)
|
||||
if hint {
|
||||
p.hint("`import future.keywords.every` for `every x in xs { ... }` expressions")
|
||||
|
||||
if p.isFutureKeyword("every") {
|
||||
// If we find a plain `every` identifier, attempt to parse an every expression,
|
||||
// add hint if it succeeds.
|
||||
if term, ok := expr.Terms.(*Term); ok && Var("every").Equal(term.Value) {
|
||||
var hint bool
|
||||
t := p.save()
|
||||
p.restore(s)
|
||||
if expr := p.futureParser().parseEvery(); expr != nil {
|
||||
_, hint = expr.Terms.(*Every)
|
||||
}
|
||||
p.restore(t)
|
||||
if hint {
|
||||
p.hint("`import future.keywords.every` for `every x in xs { ... }` expressions")
|
||||
}
|
||||
}
|
||||
}
|
||||
return expr
|
||||
}
|
||||
return nil
|
||||
return expr
|
||||
}
|
||||
|
||||
func (p *Parser) parseWith() []*With {
|
||||
@@ -1368,26 +1370,28 @@ func (p *Parser) parseSome() *Expr {
|
||||
}
|
||||
|
||||
p.restore(s)
|
||||
s = p.save() // new copy for later
|
||||
var hint bool
|
||||
p.scan()
|
||||
if term := p.futureParser().parseTermInfixCall(); term != nil {
|
||||
if call, ok := term.Value.(Call); ok {
|
||||
switch call[0].String() {
|
||||
case Member.Name, MemberWithKey.Name:
|
||||
hint = true
|
||||
|
||||
if p.isFutureKeyword("in") {
|
||||
s = p.save() // new copy for later
|
||||
var hint bool
|
||||
p.scan()
|
||||
if term := p.futureParser().parseTermInfixCall(); term != nil {
|
||||
if call, ok := term.Value.(Call); ok {
|
||||
switch call[0].String() {
|
||||
case Member.Name, MemberWithKey.Name:
|
||||
hint = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// go on as before, it's `some x[...]` or illegal
|
||||
p.restore(s)
|
||||
if hint {
|
||||
p.hint("`import future.keywords.in` for `some x in xs` expressions")
|
||||
}
|
||||
}
|
||||
|
||||
// go on as before, it's `some x[...]` or illegal
|
||||
p.restore(s)
|
||||
if hint {
|
||||
p.hint("`import future.keywords.in` for `some x in xs` expressions")
|
||||
}
|
||||
|
||||
for { // collecting var args
|
||||
|
||||
p.scan()
|
||||
|
||||
if p.s.tok != tokens.Ident {
|
||||
@@ -2566,6 +2570,7 @@ type rawAnnotation struct {
|
||||
RelatedResources []any `yaml:"related_resources"`
|
||||
Authors []any `yaml:"authors"`
|
||||
Schemas []map[string]any `yaml:"schemas"`
|
||||
Compile map[string]any `yaml:"compile"`
|
||||
Custom map[string]any `yaml:"custom"`
|
||||
}
|
||||
|
||||
@@ -2633,6 +2638,40 @@ func (b *metadataParser) Parse() (*Annotations, error) {
|
||||
result.RelatedResources = append(result.RelatedResources, rr)
|
||||
}
|
||||
|
||||
if raw.Compile != nil {
|
||||
result.Compile = &CompileAnnotation{}
|
||||
if unknowns, ok := raw.Compile["unknowns"]; ok {
|
||||
if unknowns, ok := unknowns.([]any); ok {
|
||||
result.Compile.Unknowns = make([]Ref, len(unknowns))
|
||||
for i := range unknowns {
|
||||
if unknown, ok := unknowns[i].(string); ok {
|
||||
ref, err := ParseRef(unknown)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid unknowns element %q: %w", unknown, err)
|
||||
}
|
||||
result.Compile.Unknowns[i] = ref
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if mask, ok := raw.Compile["mask_rule"]; ok {
|
||||
if mask, ok := mask.(string); ok {
|
||||
maskTerm, err := ParseTerm(mask)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid mask_rule annotation %q: %w", mask, err)
|
||||
}
|
||||
switch v := maskTerm.Value.(type) {
|
||||
case Var, String:
|
||||
result.Compile.MaskRule = Ref{maskTerm}
|
||||
case Ref:
|
||||
result.Compile.MaskRule = v
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid mask_rule annotation type %q: %[1]T", mask)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, pair := range raw.Schemas {
|
||||
k, v := unwrapPair(pair)
|
||||
|
||||
@@ -2916,6 +2955,11 @@ func IsFutureKeywordForRegoVersion(s string, v RegoVersion) bool {
|
||||
return yes
|
||||
}
|
||||
|
||||
// isFutureKeyword answers if keyword is from the "future" with the parser options set.
|
||||
func (p *Parser) isFutureKeyword(s string) bool {
|
||||
return IsFutureKeywordForRegoVersion(s, p.po.RegoVersion)
|
||||
}
|
||||
|
||||
func (p *Parser) futureImport(imp *Import, allowedFutureKeywords map[string]tokens.Token) {
|
||||
path := imp.Path.Value.(Ref)
|
||||
|
||||
|
||||
+1
-1
@@ -462,7 +462,7 @@ func (it *iterator) Next() (*storage.Update, error) {
|
||||
f := it.files[it.idx]
|
||||
it.idx++
|
||||
|
||||
isPolicy := false
|
||||
var isPolicy bool
|
||||
if strings.HasSuffix(f.name, RegoExt) {
|
||||
isPolicy = true
|
||||
}
|
||||
|
||||
+21
-15
@@ -19,21 +19,27 @@ import (
|
||||
|
||||
// Well-known metric names.
|
||||
const (
|
||||
BundleRequest = "bundle_request"
|
||||
ServerHandler = "server_handler"
|
||||
ServerQueryCacheHit = "server_query_cache_hit"
|
||||
SDKDecisionEval = "sdk_decision_eval"
|
||||
RegoQueryCompile = "rego_query_compile"
|
||||
RegoQueryEval = "rego_query_eval"
|
||||
RegoQueryParse = "rego_query_parse"
|
||||
RegoModuleParse = "rego_module_parse"
|
||||
RegoDataParse = "rego_data_parse"
|
||||
RegoModuleCompile = "rego_module_compile"
|
||||
RegoPartialEval = "rego_partial_eval"
|
||||
RegoInputParse = "rego_input_parse"
|
||||
RegoLoadFiles = "rego_load_files"
|
||||
RegoLoadBundles = "rego_load_bundles"
|
||||
RegoExternalResolve = "rego_external_resolve"
|
||||
BundleRequest = "bundle_request"
|
||||
ServerHandler = "server_handler"
|
||||
ServerQueryCacheHit = "server_query_cache_hit"
|
||||
SDKDecisionEval = "sdk_decision_eval"
|
||||
RegoQueryCompile = "rego_query_compile"
|
||||
RegoQueryEval = "rego_query_eval"
|
||||
RegoQueryParse = "rego_query_parse"
|
||||
RegoModuleParse = "rego_module_parse"
|
||||
RegoDataParse = "rego_data_parse"
|
||||
RegoModuleCompile = "rego_module_compile"
|
||||
RegoPartialEval = "rego_partial_eval"
|
||||
RegoInputParse = "rego_input_parse"
|
||||
RegoLoadFiles = "rego_load_files"
|
||||
RegoLoadBundles = "rego_load_bundles"
|
||||
RegoExternalResolve = "rego_external_resolve"
|
||||
CompilePrepPartial = "compile_prep_partial"
|
||||
CompileEvalConstraints = "compile_eval_constraints"
|
||||
CompileTranslateQueries = "compile_translate_queries"
|
||||
CompileExtractAnnotationsUnknowns = "compile_extract_annotations_unknowns"
|
||||
CompileExtractAnnotationsMask = "compile_extract_annotations_mask"
|
||||
CompileEvalMaskRule = "compile_eval_mask_rule"
|
||||
)
|
||||
|
||||
// Info contains attributes describing the underlying metrics provider.
|
||||
|
||||
+1
-2
@@ -1646,12 +1646,11 @@ func (e *eval) getRules(ref ast.Ref, args []*ast.Term) (*ast.IndexResult, error)
|
||||
|
||||
var result *ast.IndexResult
|
||||
var err error
|
||||
resolver.e = e
|
||||
if e.indexing {
|
||||
resolver.e = e
|
||||
resolver.args = args
|
||||
result, err = index.Lookup(resolver)
|
||||
} else {
|
||||
resolver.e = e
|
||||
result, err = index.AllRules(resolver)
|
||||
}
|
||||
if err != nil {
|
||||
|
||||
+1
-1
@@ -675,7 +675,7 @@ const gqlCacheName = "graphql"
|
||||
|
||||
func init() {
|
||||
|
||||
var defaultCacheEntries int = 10
|
||||
var defaultCacheEntries = 10
|
||||
var graphqlCacheConfig = cache.NamedValueCacheConfig{
|
||||
MaxNumEntries: &defaultCacheEntries,
|
||||
}
|
||||
|
||||
+8
@@ -99,6 +99,7 @@ var (
|
||||
requiredKeys = ast.NewSet(ast.InternedTerm("method"), ast.InternedTerm("url"))
|
||||
httpSendLatencyMetricKey = "rego_builtin_http_send"
|
||||
httpSendInterQueryCacheHits = httpSendLatencyMetricKey + "_interquery_cache_hits"
|
||||
httpSendNetworkRequests = httpSendLatencyMetricKey + "_network_requests"
|
||||
)
|
||||
|
||||
type httpSendKey string
|
||||
@@ -1535,6 +1536,9 @@ func (c *interQueryCache) ExecuteHTTPRequest() (*http.Response, error) {
|
||||
return nil, handleHTTPSendErr(c.bctx, err)
|
||||
}
|
||||
|
||||
// Increment counter for actual network requests
|
||||
c.bctx.Metrics.Counter(httpSendNetworkRequests).Incr()
|
||||
|
||||
return executeHTTPRequest(c.httpReq, c.httpClient, c.req)
|
||||
}
|
||||
|
||||
@@ -1586,6 +1590,10 @@ func (c *intraQueryCache) ExecuteHTTPRequest() (*http.Response, error) {
|
||||
if err != nil {
|
||||
return nil, handleHTTPSendErr(c.bctx, err)
|
||||
}
|
||||
|
||||
// Increment counter for actual network requests
|
||||
c.bctx.Metrics.Counter(httpSendNetworkRequests).Incr()
|
||||
|
||||
return executeHTTPRequest(httpReq, httpClient, c.req)
|
||||
}
|
||||
|
||||
|
||||
+8
-7
@@ -15,8 +15,10 @@ import (
|
||||
|
||||
type randIntCachingKey string
|
||||
|
||||
var zero = big.NewInt(0)
|
||||
var one = big.NewInt(1)
|
||||
var (
|
||||
zero = big.NewInt(0)
|
||||
one = big.NewInt(1)
|
||||
)
|
||||
|
||||
func builtinNumbersRange(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
|
||||
if canGenerateCheapRange(operands) {
|
||||
@@ -45,8 +47,9 @@ func builtinNumbersRangeStep(bctx BuiltinContext, operands []*ast.Term, iter fun
|
||||
if canGenerateCheapRangeStep(operands) {
|
||||
step, _ := builtins.IntOperand(operands[2].Value, 3)
|
||||
if step <= 0 {
|
||||
return errors.New("numbers.range_step: step must be a positive number above zero")
|
||||
return errors.New("numbers.range_step: step must be a positive integer")
|
||||
}
|
||||
|
||||
return generateCheapRange(operands, step, iter)
|
||||
}
|
||||
|
||||
@@ -66,7 +69,7 @@ func builtinNumbersRangeStep(bctx BuiltinContext, operands []*ast.Term, iter fun
|
||||
}
|
||||
|
||||
if step.Cmp(zero) <= 0 {
|
||||
return errors.New("numbers.range_step: step must be a positive number above zero")
|
||||
return errors.New("numbers.range_step: step must be a positive integer")
|
||||
}
|
||||
|
||||
ast, err := generateRange(bctx, x, y, step, "numbers.range_step")
|
||||
@@ -158,11 +161,9 @@ func generateRange(bctx BuiltinContext, x *big.Int, y *big.Int, step *big.Int, f
|
||||
}
|
||||
|
||||
func builtinRandIntn(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
|
||||
|
||||
strOp, err := builtins.StringOperand(operands[0].Value, 1)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
}
|
||||
|
||||
n, err := builtins.IntOperand(operands[1].Value, 2)
|
||||
@@ -178,7 +179,7 @@ func builtinRandIntn(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.T
|
||||
n = -n
|
||||
}
|
||||
|
||||
var key = randIntCachingKey(fmt.Sprintf("%s-%d", strOp, n))
|
||||
key := randIntCachingKey(fmt.Sprintf("%s-%d", strOp, n))
|
||||
|
||||
if val, ok := bctx.Cache.Get(key); ok {
|
||||
return iter(val.(*ast.Term))
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ import (
|
||||
"runtime/debug"
|
||||
)
|
||||
|
||||
var Version = "1.8.0"
|
||||
var Version = "1.9.0"
|
||||
|
||||
// GoVersion is the version of Go this was built with
|
||||
var GoVersion = runtime.Version()
|
||||
|
||||
Reference in New Issue
Block a user