Bump cel-go to v0.16.0

This commit is contained in:
Joe Betz
2023-05-26 18:06:11 -04:00
parent d05b79c836
commit 5c0b59891d
198 changed files with 18207 additions and 2988 deletions

View File

@@ -15,7 +15,7 @@
package interpreter
import (
"math"
"fmt"
"github.com/google/cel-go/common/operators"
"github.com/google/cel-go/common/overloads"
@@ -64,10 +64,18 @@ type InterpretableAttribute interface {
// Qualify replicates the Attribute.Qualify method to permit extension and interception
// of object qualification.
Qualify(vars Activation, obj interface{}) (interface{}, error)
Qualify(vars Activation, obj any) (any, error)
// QualifyIfPresent qualifies the object if the qualifier is declared or defined on the object.
// The 'presenceOnly' flag indicates that the value is not necessary, just a boolean status as
// to whether the qualifier is present.
QualifyIfPresent(vars Activation, obj any, presenceOnly bool) (any, bool, error)
// IsOptional indicates whether the resulting value is an optional type.
IsOptional() bool
// Resolve returns the value of the Attribute given the current Activation.
Resolve(Activation) (interface{}, error)
Resolve(Activation) (any, error)
}
// InterpretableCall interface for inspecting Interpretable instructions related to function calls.
@@ -103,10 +111,8 @@ type InterpretableConstructor interface {
// Core Interpretable implementations used during the program planning phase.
type evalTestOnly struct {
id int64
op Interpretable
field types.String
fieldType *ref.FieldType
id int64
InterpretableAttribute
}
// ID implements the Interpretable interface method.
@@ -116,44 +122,55 @@ func (test *evalTestOnly) ID() int64 {
// Eval implements the Interpretable interface method.
func (test *evalTestOnly) Eval(ctx Activation) ref.Val {
// Handle field selection on a proto in the most efficient way possible.
if test.fieldType != nil {
opAttr, ok := test.op.(InterpretableAttribute)
if ok {
opVal, err := opAttr.Resolve(ctx)
if err != nil {
return types.NewErr(err.Error())
}
refVal, ok := opVal.(ref.Val)
if ok {
opVal = refVal.Value()
}
if test.fieldType.IsSet(opVal) {
return types.True
}
return types.False
}
val, err := test.Resolve(ctx)
// Return an error if the resolve step fails
if err != nil {
return types.WrapErr(err)
}
obj := test.op.Eval(ctx)
tester, ok := obj.(traits.FieldTester)
if ok {
return tester.IsSet(test.field)
if optVal, isOpt := val.(*types.Optional); isOpt {
return types.Bool(optVal.HasValue())
}
container, ok := obj.(traits.Container)
if ok {
return container.Contains(test.field)
}
return types.ValOrErr(obj, "invalid type for field selection.")
return test.Adapter().NativeToValue(val)
}
// Cost provides the heuristic cost of a `has(field)` macro. The cost has at least 1 for determining
// if the field exists, apart from the cost of accessing the field.
func (test *evalTestOnly) Cost() (min, max int64) {
min, max = estimateCost(test.op)
min++
max++
return
// AddQualifier appends a qualifier that will always and only perform a presence test.
func (test *evalTestOnly) AddQualifier(q Qualifier) (Attribute, error) {
cq, ok := q.(ConstantQualifier)
if !ok {
return nil, fmt.Errorf("test only expressions must have constant qualifiers: %v", q)
}
return test.InterpretableAttribute.AddQualifier(&testOnlyQualifier{ConstantQualifier: cq})
}
type testOnlyQualifier struct {
ConstantQualifier
}
// Qualify determines whether the test-only qualifier is present on the input object.
func (q *testOnlyQualifier) Qualify(vars Activation, obj any) (any, error) {
out, present, err := q.ConstantQualifier.QualifyIfPresent(vars, obj, true)
if err != nil {
return nil, err
}
if unk, isUnk := out.(types.Unknown); isUnk {
return unk, nil
}
if opt, isOpt := out.(types.Optional); isOpt {
return opt.HasValue(), nil
}
return present, nil
}
// QualifyIfPresent returns whether the target field in the test-only expression is present.
func (q *testOnlyQualifier) QualifyIfPresent(vars Activation, obj any, presenceOnly bool) (any, bool, error) {
// Only ever test for presence.
return q.ConstantQualifier.QualifyIfPresent(vars, obj, true)
}
// QualifierValueEquals determines whether the test-only constant qualifier equals the input value.
func (q *testOnlyQualifier) QualifierValueEquals(value any) bool {
// The input qualifier will always be of type string
return q.ConstantQualifier.Value().Value() == value
}
// NewConstValue creates a new constant valued Interpretable.
@@ -179,11 +196,6 @@ func (cons *evalConst) Eval(ctx Activation) ref.Val {
return cons.val
}
// Cost returns zero for a constant valued Interpretable.
func (cons *evalConst) Cost() (min, max int64) {
return 0, 0
}
// Value implements the InterpretableConst interface method.
func (cons *evalConst) Value() ref.Val {
return cons.val
@@ -233,12 +245,6 @@ func (or *evalOr) Eval(ctx Activation) ref.Val {
return types.ValOrErr(rVal, "no such overload")
}
// Cost implements the Coster interface method. The minimum possible cost incurs when the left-hand
// side expr is sufficient in determining the evaluation result.
func (or *evalOr) Cost() (min, max int64) {
return calShortCircuitBinaryOpsCost(or.lhs, or.rhs)
}
type evalAnd struct {
id int64
lhs Interpretable
@@ -283,18 +289,6 @@ func (and *evalAnd) Eval(ctx Activation) ref.Val {
return types.ValOrErr(rVal, "no such overload")
}
// Cost implements the Coster interface method. The minimum possible cost incurs when the left-hand
// side expr is sufficient in determining the evaluation result.
func (and *evalAnd) Cost() (min, max int64) {
return calShortCircuitBinaryOpsCost(and.lhs, and.rhs)
}
func calShortCircuitBinaryOpsCost(lhs, rhs Interpretable) (min, max int64) {
lMin, lMax := estimateCost(lhs)
_, rMax := estimateCost(rhs)
return lMin, lMax + rMax + 1
}
type evalEq struct {
id int64
lhs Interpretable
@@ -319,11 +313,6 @@ func (eq *evalEq) Eval(ctx Activation) ref.Val {
return types.Equal(lVal, rVal)
}
// Cost implements the Coster interface method.
func (eq *evalEq) Cost() (min, max int64) {
return calExhaustiveBinaryOpsCost(eq.lhs, eq.rhs)
}
// Function implements the InterpretableCall interface method.
func (*evalEq) Function() string {
return operators.Equals
@@ -363,11 +352,6 @@ func (ne *evalNe) Eval(ctx Activation) ref.Val {
return types.Bool(types.Equal(lVal, rVal) != types.True)
}
// Cost implements the Coster interface method.
func (ne *evalNe) Cost() (min, max int64) {
return calExhaustiveBinaryOpsCost(ne.lhs, ne.rhs)
}
// Function implements the InterpretableCall interface method.
func (*evalNe) Function() string {
return operators.NotEquals
@@ -400,11 +384,6 @@ func (zero *evalZeroArity) Eval(ctx Activation) ref.Val {
return zero.impl()
}
// Cost returns 1 representing the heuristic cost of the function.
func (zero *evalZeroArity) Cost() (min, max int64) {
return 1, 1
}
// Function implements the InterpretableCall interface method.
func (zero *evalZeroArity) Function() string {
return zero.function
@@ -456,14 +435,6 @@ func (un *evalUnary) Eval(ctx Activation) ref.Val {
return types.NewErr("no such overload: %s", un.function)
}
// Cost implements the Coster interface method.
func (un *evalUnary) Cost() (min, max int64) {
min, max = estimateCost(un.arg)
min++ // add cost for function
max++
return
}
// Function implements the InterpretableCall interface method.
func (un *evalUnary) Function() string {
return un.function
@@ -522,11 +493,6 @@ func (bin *evalBinary) Eval(ctx Activation) ref.Val {
return types.NewErr("no such overload: %s", bin.function)
}
// Cost implements the Coster interface method.
func (bin *evalBinary) Cost() (min, max int64) {
return calExhaustiveBinaryOpsCost(bin.lhs, bin.rhs)
}
// Function implements the InterpretableCall interface method.
func (bin *evalBinary) Function() string {
return bin.function
@@ -593,14 +559,6 @@ func (fn *evalVarArgs) Eval(ctx Activation) ref.Val {
return types.NewErr("no such overload: %s", fn.function)
}
// Cost implements the Coster interface method.
func (fn *evalVarArgs) Cost() (min, max int64) {
min, max = sumOfCost(fn.args)
min++ // add cost for function
max++
return
}
// Function implements the InterpretableCall interface method.
func (fn *evalVarArgs) Function() string {
return fn.function
@@ -617,9 +575,11 @@ func (fn *evalVarArgs) Args() []Interpretable {
}
type evalList struct {
id int64
elems []Interpretable
adapter ref.TypeAdapter
id int64
elems []Interpretable
optionals []bool
hasOptionals bool
adapter ref.TypeAdapter
}
// ID implements the Interpretable interface method.
@@ -629,14 +589,24 @@ func (l *evalList) ID() int64 {
// Eval implements the Interpretable interface method.
func (l *evalList) Eval(ctx Activation) ref.Val {
elemVals := make([]ref.Val, len(l.elems))
elemVals := make([]ref.Val, 0, len(l.elems))
// If any argument is unknown or error early terminate.
for i, elem := range l.elems {
elemVal := elem.Eval(ctx)
if types.IsUnknownOrError(elemVal) {
return elemVal
}
elemVals[i] = elemVal
if l.hasOptionals && l.optionals[i] {
optVal, ok := elemVal.(*types.Optional)
if !ok {
return invalidOptionalElementInit(elemVal)
}
if !optVal.HasValue() {
continue
}
elemVal = optVal.GetValue()
}
elemVals = append(elemVals, elemVal)
}
return l.adapter.NativeToValue(elemVals)
}
@@ -649,16 +619,13 @@ func (l *evalList) Type() ref.Type {
return types.ListType
}
// Cost implements the Coster interface method.
func (l *evalList) Cost() (min, max int64) {
return sumOfCost(l.elems)
}
type evalMap struct {
id int64
keys []Interpretable
vals []Interpretable
adapter ref.TypeAdapter
id int64
keys []Interpretable
vals []Interpretable
optionals []bool
hasOptionals bool
adapter ref.TypeAdapter
}
// ID implements the Interpretable interface method.
@@ -679,6 +646,17 @@ func (m *evalMap) Eval(ctx Activation) ref.Val {
if types.IsUnknownOrError(valVal) {
return valVal
}
if m.hasOptionals && m.optionals[i] {
optVal, ok := valVal.(*types.Optional)
if !ok {
return invalidOptionalEntryInit(keyVal, valVal)
}
if !optVal.HasValue() {
delete(entries, keyVal)
continue
}
valVal = optVal.GetValue()
}
entries[keyVal] = valVal
}
return m.adapter.NativeToValue(entries)
@@ -704,19 +682,14 @@ func (m *evalMap) Type() ref.Type {
return types.MapType
}
// Cost implements the Coster interface method.
func (m *evalMap) Cost() (min, max int64) {
kMin, kMax := sumOfCost(m.keys)
vMin, vMax := sumOfCost(m.vals)
return kMin + vMin, kMax + vMax
}
type evalObj struct {
id int64
typeName string
fields []string
vals []Interpretable
provider ref.TypeProvider
id int64
typeName string
fields []string
vals []Interpretable
optionals []bool
hasOptionals bool
provider ref.TypeProvider
}
// ID implements the Interpretable interface method.
@@ -733,6 +706,17 @@ func (o *evalObj) Eval(ctx Activation) ref.Val {
if types.IsUnknownOrError(val) {
return val
}
if o.hasOptionals && o.optionals[i] {
optVal, ok := val.(*types.Optional)
if !ok {
return invalidOptionalEntryInit(field, val)
}
if !optVal.HasValue() {
delete(fieldVals, field)
continue
}
val = optVal.GetValue()
}
fieldVals[field] = val
}
return o.provider.NewValue(o.typeName, fieldVals)
@@ -746,21 +730,6 @@ func (o *evalObj) Type() ref.Type {
return types.NewObjectTypeValue(o.typeName)
}
// Cost implements the Coster interface method.
func (o *evalObj) Cost() (min, max int64) {
return sumOfCost(o.vals)
}
func sumOfCost(interps []Interpretable) (min, max int64) {
min, max = 0, 0
for _, in := range interps {
minT, maxT := estimateCost(in)
min += minT
max += maxT
}
return
}
type evalFold struct {
id int64
accuVar string
@@ -842,38 +811,6 @@ func (fold *evalFold) Eval(ctx Activation) ref.Val {
return res
}
// Cost implements the Coster interface method.
func (fold *evalFold) Cost() (min, max int64) {
// Compute the cost for evaluating iterRange.
iMin, iMax := estimateCost(fold.iterRange)
// Compute the size of iterRange. If the size depends on the input, return the maximum possible
// cost range.
foldRange := fold.iterRange.Eval(EmptyActivation())
if !foldRange.Type().HasTrait(traits.IterableType) {
return 0, math.MaxInt64
}
var rangeCnt int64
it := foldRange.(traits.Iterable).Iterator()
for it.HasNext() == types.True {
it.Next()
rangeCnt++
}
aMin, aMax := estimateCost(fold.accu)
cMin, cMax := estimateCost(fold.cond)
sMin, sMax := estimateCost(fold.step)
rMin, rMax := estimateCost(fold.result)
if fold.exhaustive {
cMin = cMin * rangeCnt
sMin = sMin * rangeCnt
}
// The cond and step costs are multiplied by size(iterRange). The minimum possible cost incurs
// when the evaluation result can be determined by the first iteration.
return iMin + aMin + cMin + sMin + rMin,
iMax + aMax + cMax*rangeCnt + sMax*rangeCnt + rMax
}
// Optional Interpretable implementations that specialize, subsume, or extend the core evaluation
// plan via decorators.
@@ -893,17 +830,15 @@ func (e *evalSetMembership) ID() int64 {
// Eval implements the Interpretable interface method.
func (e *evalSetMembership) Eval(ctx Activation) ref.Val {
val := e.arg.Eval(ctx)
if types.IsUnknownOrError(val) {
return val
}
if ret, found := e.valueSet[val]; found {
return ret
}
return types.False
}
// Cost implements the Coster interface method.
func (e *evalSetMembership) Cost() (min, max int64) {
return estimateCost(e.arg)
}
// evalWatch is an Interpretable implementation that wraps the execution of a given
// expression so that it may observe the computed value and send it to an observer.
type evalWatch struct {
@@ -918,15 +853,10 @@ func (e *evalWatch) Eval(ctx Activation) ref.Val {
return val
}
// Cost implements the Coster interface method.
func (e *evalWatch) Cost() (min, max int64) {
return estimateCost(e.Interpretable)
}
// evalWatchAttr describes a watcher of an instAttr Interpretable.
// evalWatchAttr describes a watcher of an InterpretableAttribute Interpretable.
//
// Since the watcher may be selected against at a later stage in program planning, the watcher
// must implement the instAttr interface by proxy.
// must implement the InterpretableAttribute interface by proxy.
type evalWatchAttr struct {
InterpretableAttribute
observer EvalObserver
@@ -953,11 +883,6 @@ func (e *evalWatchAttr) AddQualifier(q Qualifier) (Attribute, error) {
return e, err
}
// Cost implements the Coster interface method.
func (e *evalWatchAttr) Cost() (min, max int64) {
return estimateCost(e.InterpretableAttribute)
}
// Eval implements the Interpretable interface method.
func (e *evalWatchAttr) Eval(vars Activation) ref.Val {
val := e.InterpretableAttribute.Eval(vars)
@@ -973,17 +898,12 @@ type evalWatchConstQual struct {
adapter ref.TypeAdapter
}
// Cost implements the Coster interface method.
func (e *evalWatchConstQual) Cost() (min, max int64) {
return estimateCost(e.ConstantQualifier)
}
// Qualify observes the qualification of a object via a constant boolean, int, string, or uint.
func (e *evalWatchConstQual) Qualify(vars Activation, obj interface{}) (interface{}, error) {
func (e *evalWatchConstQual) Qualify(vars Activation, obj any) (any, error) {
out, err := e.ConstantQualifier.Qualify(vars, obj)
var val ref.Val
if err != nil {
val = types.NewErr(err.Error())
val = types.WrapErr(err)
} else {
val = e.adapter.NativeToValue(out)
}
@@ -991,8 +911,25 @@ func (e *evalWatchConstQual) Qualify(vars Activation, obj interface{}) (interfac
return out, err
}
// QualifyIfPresent conditionally qualifies the variable and only records a value if one is present.
func (e *evalWatchConstQual) QualifyIfPresent(vars Activation, obj any, presenceOnly bool) (any, bool, error) {
out, present, err := e.ConstantQualifier.QualifyIfPresent(vars, obj, presenceOnly)
var val ref.Val
if err != nil {
val = types.WrapErr(err)
} else if out != nil {
val = e.adapter.NativeToValue(out)
} else if presenceOnly {
val = types.Bool(present)
}
if present || presenceOnly {
e.observer(e.ID(), e.ConstantQualifier, val)
}
return out, present, err
}
// QualifierValueEquals tests whether the incoming value is equal to the qualifying constant.
func (e *evalWatchConstQual) QualifierValueEquals(value interface{}) bool {
func (e *evalWatchConstQual) QualifierValueEquals(value any) bool {
qve, ok := e.ConstantQualifier.(qualifierValueEquator)
return ok && qve.QualifierValueEquals(value)
}
@@ -1004,17 +941,12 @@ type evalWatchQual struct {
adapter ref.TypeAdapter
}
// Cost implements the Coster interface method.
func (e *evalWatchQual) Cost() (min, max int64) {
return estimateCost(e.Qualifier)
}
// Qualify observes the qualification of a object via a value computed at runtime.
func (e *evalWatchQual) Qualify(vars Activation, obj interface{}) (interface{}, error) {
func (e *evalWatchQual) Qualify(vars Activation, obj any) (any, error) {
out, err := e.Qualifier.Qualify(vars, obj)
var val ref.Val
if err != nil {
val = types.NewErr(err.Error())
val = types.WrapErr(err)
} else {
val = e.adapter.NativeToValue(out)
}
@@ -1022,6 +954,23 @@ func (e *evalWatchQual) Qualify(vars Activation, obj interface{}) (interface{},
return out, err
}
// QualifyIfPresent conditionally qualifies the variable and only records a value if one is present.
func (e *evalWatchQual) QualifyIfPresent(vars Activation, obj any, presenceOnly bool) (any, bool, error) {
out, present, err := e.Qualifier.QualifyIfPresent(vars, obj, presenceOnly)
var val ref.Val
if err != nil {
val = types.WrapErr(err)
} else if out != nil {
val = e.adapter.NativeToValue(out)
} else if presenceOnly {
val = types.Bool(present)
}
if present || presenceOnly {
e.observer(e.ID(), e.Qualifier, val)
}
return out, present, err
}
// evalWatchConst describes a watcher of an instConst Interpretable.
type evalWatchConst struct {
InterpretableConst
@@ -1035,11 +984,6 @@ func (e *evalWatchConst) Eval(vars Activation) ref.Val {
return val
}
// Cost implements the Coster interface method.
func (e *evalWatchConst) Cost() (min, max int64) {
return estimateCost(e.InterpretableConst)
}
// evalExhaustiveOr is just like evalOr, but does not short-circuit argument evaluation.
type evalExhaustiveOr struct {
id int64
@@ -1078,12 +1022,7 @@ func (or *evalExhaustiveOr) Eval(ctx Activation) ref.Val {
if types.IsError(lVal) {
return lVal
}
return types.ValOrErr(rVal, "no such overload")
}
// Cost implements the Coster interface method.
func (or *evalExhaustiveOr) Cost() (min, max int64) {
return calExhaustiveBinaryOpsCost(or.lhs, or.rhs)
return types.MaybeNoSuchOverloadErr(rVal)
}
// evalExhaustiveAnd is just like evalAnd, but does not short-circuit argument evaluation.
@@ -1124,18 +1063,7 @@ func (and *evalExhaustiveAnd) Eval(ctx Activation) ref.Val {
if types.IsError(lVal) {
return lVal
}
return types.ValOrErr(rVal, "no such overload")
}
// Cost implements the Coster interface method.
func (and *evalExhaustiveAnd) Cost() (min, max int64) {
return calExhaustiveBinaryOpsCost(and.lhs, and.rhs)
}
func calExhaustiveBinaryOpsCost(lhs, rhs Interpretable) (min, max int64) {
lMin, lMax := estimateCost(lhs)
rMin, rMax := estimateCost(rhs)
return lMin + rMin + 1, lMax + rMax + 1
return types.MaybeNoSuchOverloadErr(rVal)
}
// evalExhaustiveConditional is like evalConditional, but does not short-circuit argument
@@ -1154,77 +1082,114 @@ func (cond *evalExhaustiveConditional) ID() int64 {
// Eval implements the Interpretable interface method.
func (cond *evalExhaustiveConditional) Eval(ctx Activation) ref.Val {
cVal := cond.attr.expr.Eval(ctx)
tVal, err := cond.attr.truthy.Resolve(ctx)
if err != nil {
return types.NewErr(err.Error())
}
fVal, err := cond.attr.falsy.Resolve(ctx)
if err != nil {
return types.NewErr(err.Error())
}
tVal, tErr := cond.attr.truthy.Resolve(ctx)
fVal, fErr := cond.attr.falsy.Resolve(ctx)
cBool, ok := cVal.(types.Bool)
if !ok {
return types.ValOrErr(cVal, "no such overload")
}
if cBool {
if tErr != nil {
return types.WrapErr(tErr)
}
return cond.adapter.NativeToValue(tVal)
}
if fErr != nil {
return types.WrapErr(fErr)
}
return cond.adapter.NativeToValue(fVal)
}
// Cost implements the Coster interface method.
func (cond *evalExhaustiveConditional) Cost() (min, max int64) {
return cond.attr.Cost()
}
// evalAttr evaluates an Attribute value.
type evalAttr struct {
adapter ref.TypeAdapter
attr Attribute
adapter ref.TypeAdapter
attr Attribute
optional bool
}
var _ InterpretableAttribute = &evalAttr{}
// ID of the attribute instruction.
func (a *evalAttr) ID() int64 {
return a.attr.ID()
}
// AddQualifier implements the instAttr interface method.
// AddQualifier implements the InterpretableAttribute interface method.
func (a *evalAttr) AddQualifier(qual Qualifier) (Attribute, error) {
attr, err := a.attr.AddQualifier(qual)
a.attr = attr
return attr, err
}
// Attr implements the instAttr interface method.
// Attr implements the InterpretableAttribute interface method.
func (a *evalAttr) Attr() Attribute {
return a.attr
}
// Adapter implements the instAttr interface method.
// Adapter implements the InterpretableAttribute interface method.
func (a *evalAttr) Adapter() ref.TypeAdapter {
return a.adapter
}
// Cost implements the Coster interface method.
func (a *evalAttr) Cost() (min, max int64) {
return estimateCost(a.attr)
}
// Eval implements the Interpretable interface method.
func (a *evalAttr) Eval(ctx Activation) ref.Val {
v, err := a.attr.Resolve(ctx)
if err != nil {
return types.NewErr(err.Error())
return types.WrapErr(err)
}
return a.adapter.NativeToValue(v)
}
// Qualify proxies to the Attribute's Qualify method.
func (a *evalAttr) Qualify(ctx Activation, obj interface{}) (interface{}, error) {
func (a *evalAttr) Qualify(ctx Activation, obj any) (any, error) {
return a.attr.Qualify(ctx, obj)
}
// QualifyIfPresent proxies to the Attribute's QualifyIfPresent method.
func (a *evalAttr) QualifyIfPresent(ctx Activation, obj any, presenceOnly bool) (any, bool, error) {
return a.attr.QualifyIfPresent(ctx, obj, presenceOnly)
}
func (a *evalAttr) IsOptional() bool {
return a.optional
}
// Resolve proxies to the Attribute's Resolve method.
func (a *evalAttr) Resolve(ctx Activation) (interface{}, error) {
func (a *evalAttr) Resolve(ctx Activation) (any, error) {
return a.attr.Resolve(ctx)
}
type evalWatchConstructor struct {
constructor InterpretableConstructor
observer EvalObserver
}
// InitVals implements the InterpretableConstructor InitVals function.
func (c *evalWatchConstructor) InitVals() []Interpretable {
return c.constructor.InitVals()
}
// Type implements the InterpretableConstructor Type function.
func (c *evalWatchConstructor) Type() ref.Type {
return c.constructor.Type()
}
// ID implements the Interpretable ID function.
func (c *evalWatchConstructor) ID() int64 {
return c.constructor.ID()
}
// Eval implements the Interpretable Eval function.
func (c *evalWatchConstructor) Eval(ctx Activation) ref.Val {
val := c.constructor.Eval(ctx)
c.observer(c.ID(), c.constructor, val)
return val
}
func invalidOptionalEntryInit(field any, value ref.Val) ref.Val {
return types.NewErr("cannot initialize optional entry '%v' from non-optional value %v", field, value)
}
func invalidOptionalElementInit(value ref.Val) ref.Val {
return types.NewErr("cannot initialize optional list element from non-optional value %v", value)
}