package interpreter
import (
"fmt"
"github.com/google/cel-go/common/functions"
"github.com/google/cel-go/common/operators"
"github.com/google/cel-go/common/overloads"
"github.com/google/cel-go/common/types"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/common/types/traits"
)
type Interpretable interface {
ID() int64
Eval(activation Activation) ref.Val
}
type InterpretableConst interface {
Interpretable
Value() ref.Val
}
type InterpretableAttribute interface {
Interpretable
Attr() Attribute
Adapter() types.Adapter
AddQualifier(Qualifier) (Attribute, error)
Qualify(vars Activation, obj any) (any, error)
QualifyIfPresent(vars Activation, obj any, presenceOnly bool) (any, bool, error)
IsOptional() bool
Resolve(Activation) (any, error)
}
type InterpretableCall interface {
Interpretable
Function() string
OverloadID() string
Args() []Interpretable
}
type InterpretableConstructor interface {
Interpretable
InitVals() []Interpretable
Type() ref.Type
}
type evalTestOnly struct {
id int64
InterpretableAttribute
}
func (test *evalTestOnly) ID() int64 {
return test.id
}
func (test *evalTestOnly) Eval(ctx Activation) ref.Val {
val, err := test.Resolve(ctx)
if err != nil {
return types.WrapErr(err)
}
if optVal, isOpt := val.(*types.Optional); isOpt {
return types.Bool(optVal.HasValue())
}
return test.Adapter().NativeToValue(val)
}
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
}
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
}
func (q *testOnlyQualifier) QualifyIfPresent(vars Activation, obj any, presenceOnly bool) (any, bool, error) {
return q.ConstantQualifier.QualifyIfPresent(vars, obj, true)
}
func (q *testOnlyQualifier) QualifierValueEquals(value any) bool {
return q.ConstantQualifier.Value().Value() == value
}
func NewConstValue(id int64, val ref.Val) InterpretableConst {
return &evalConst{
id: id,
val: val,
}
}
type evalConst struct {
id int64
val ref.Val
}
func (cons *evalConst) ID() int64 {
return cons.id
}
func (cons *evalConst) Eval(ctx Activation) ref.Val {
return cons.val
}
func (cons *evalConst) Value() ref.Val {
return cons.val
}
type evalOr struct {
id int64
terms []Interpretable
}
func (or *evalOr) ID() int64 {
return or.id
}
func (or *evalOr) Eval(ctx Activation) ref.Val {
var err ref.Val = nil
var unk *types.Unknown
for _, term := range or.terms {
val := term.Eval(ctx)
boolVal, ok := val.(types.Bool)
if ok && boolVal == types.True {
return types.True
}
if !ok {
isUnk := false
unk, isUnk = types.MaybeMergeUnknowns(val, unk)
if !isUnk && err == nil {
if types.IsError(val) {
err = val
} else {
err = types.MaybeNoSuchOverloadErr(val)
}
}
}
}
if unk != nil {
return unk
}
if err != nil {
return err
}
return types.False
}
type evalAnd struct {
id int64
terms []Interpretable
}
func (and *evalAnd) ID() int64 {
return and.id
}
func (and *evalAnd) Eval(ctx Activation) ref.Val {
var err ref.Val = nil
var unk *types.Unknown
for _, term := range and.terms {
val := term.Eval(ctx)
boolVal, ok := val.(types.Bool)
if ok && boolVal == types.False {
return types.False
}
if !ok {
isUnk := false
unk, isUnk = types.MaybeMergeUnknowns(val, unk)
if !isUnk && err == nil {
if types.IsError(val) {
err = val
} else {
err = types.MaybeNoSuchOverloadErr(val)
}
}
}
}
if unk != nil {
return unk
}
if err != nil {
return err
}
return types.True
}
type evalEq struct {
id int64
lhs Interpretable
rhs Interpretable
}
func (eq *evalEq) ID() int64 {
return eq.id
}
func (eq *evalEq) Eval(ctx Activation) ref.Val {
lVal := eq.lhs.Eval(ctx)
rVal := eq.rhs.Eval(ctx)
if types.IsUnknownOrError(lVal) {
return lVal
}
if types.IsUnknownOrError(rVal) {
return rVal
}
return types.Equal(lVal, rVal)
}
func (*evalEq) Function() string {
return operators.Equals
}
func (*evalEq) OverloadID() string {
return overloads.Equals
}
func (eq *evalEq) Args() []Interpretable {
return []Interpretable{eq.lhs, eq.rhs}
}
type evalNe struct {
id int64
lhs Interpretable
rhs Interpretable
}
func (ne *evalNe) ID() int64 {
return ne.id
}
func (ne *evalNe) Eval(ctx Activation) ref.Val {
lVal := ne.lhs.Eval(ctx)
rVal := ne.rhs.Eval(ctx)
if types.IsUnknownOrError(lVal) {
return lVal
}
if types.IsUnknownOrError(rVal) {
return rVal
}
return types.Bool(types.Equal(lVal, rVal) != types.True)
}
func (*evalNe) Function() string {
return operators.NotEquals
}
func (*evalNe) OverloadID() string {
return overloads.NotEquals
}
func (ne *evalNe) Args() []Interpretable {
return []Interpretable{ne.lhs, ne.rhs}
}
type evalZeroArity struct {
id int64
function string
overload string
impl functions.FunctionOp
}
func (zero *evalZeroArity) ID() int64 {
return zero.id
}
func (zero *evalZeroArity) Eval(ctx Activation) ref.Val {
return zero.impl()
}
func (zero *evalZeroArity) Function() string {
return zero.function
}
func (zero *evalZeroArity) OverloadID() string {
return zero.overload
}
func (zero *evalZeroArity) Args() []Interpretable {
return []Interpretable{}
}
type evalUnary struct {
id int64
function string
overload string
arg Interpretable
trait int
impl functions.UnaryOp
nonStrict bool
}
func (un *evalUnary) ID() int64 {
return un.id
}
func (un *evalUnary) Eval(ctx Activation) ref.Val {
argVal := un.arg.Eval(ctx)
strict := !un.nonStrict
if strict && types.IsUnknownOrError(argVal) {
return argVal
}
if un.impl != nil && (un.trait == 0 || (!strict && types.IsUnknownOrError(argVal)) || argVal.Type().HasTrait(un.trait)) {
return un.impl(argVal)
}
if argVal.Type().HasTrait(traits.ReceiverType) {
return argVal.(traits.Receiver).Receive(un.function, un.overload, []ref.Val{})
}
return types.NewErr("no such overload: %s", un.function)
}
func (un *evalUnary) Function() string {
return un.function
}
func (un *evalUnary) OverloadID() string {
return un.overload
}
func (un *evalUnary) Args() []Interpretable {
return []Interpretable{un.arg}
}
type evalBinary struct {
id int64
function string
overload string
lhs Interpretable
rhs Interpretable
trait int
impl functions.BinaryOp
nonStrict bool
}
func (bin *evalBinary) ID() int64 {
return bin.id
}
func (bin *evalBinary) Eval(ctx Activation) ref.Val {
lVal := bin.lhs.Eval(ctx)
rVal := bin.rhs.Eval(ctx)
strict := !bin.nonStrict
if strict {
if types.IsUnknownOrError(lVal) {
return lVal
}
if types.IsUnknownOrError(rVal) {
return rVal
}
}
if bin.impl != nil && (bin.trait == 0 || (!strict && types.IsUnknownOrError(lVal)) || lVal.Type().HasTrait(bin.trait)) {
return bin.impl(lVal, rVal)
}
if lVal.Type().HasTrait(traits.ReceiverType) {
return lVal.(traits.Receiver).Receive(bin.function, bin.overload, []ref.Val{rVal})
}
return types.NewErr("no such overload: %s", bin.function)
}
func (bin *evalBinary) Function() string {
return bin.function
}
func (bin *evalBinary) OverloadID() string {
return bin.overload
}
func (bin *evalBinary) Args() []Interpretable {
return []Interpretable{bin.lhs, bin.rhs}
}
type evalVarArgs struct {
id int64
function string
overload string
args []Interpretable
trait int
impl functions.FunctionOp
nonStrict bool
}
func NewCall(id int64, function, overload string, args []Interpretable, impl functions.FunctionOp) InterpretableCall {
return &evalVarArgs{
id: id,
function: function,
overload: overload,
args: args,
impl: impl,
}
}
func (fn *evalVarArgs) ID() int64 {
return fn.id
}
func (fn *evalVarArgs) Eval(ctx Activation) ref.Val {
argVals := make([]ref.Val, len(fn.args))
strict := !fn.nonStrict
for i, arg := range fn.args {
argVals[i] = arg.Eval(ctx)
if strict && types.IsUnknownOrError(argVals[i]) {
return argVals[i]
}
}
arg0 := argVals[0]
if fn.impl != nil && (fn.trait == 0 || (!strict && types.IsUnknownOrError(arg0)) || arg0.Type().HasTrait(fn.trait)) {
return fn.impl(argVals...)
}
if arg0.Type().HasTrait(traits.ReceiverType) {
return arg0.(traits.Receiver).Receive(fn.function, fn.overload, argVals[1:])
}
return types.NewErr("no such overload: %s", fn.function)
}
func (fn *evalVarArgs) Function() string {
return fn.function
}
func (fn *evalVarArgs) OverloadID() string {
return fn.overload
}
func (fn *evalVarArgs) Args() []Interpretable {
return fn.args
}
type evalList struct {
id int64
elems []Interpretable
optionals []bool
hasOptionals bool
adapter types.Adapter
}
func (l *evalList) ID() int64 {
return l.id
}
func (l *evalList) Eval(ctx Activation) ref.Val {
elemVals := make([]ref.Val, 0, len(l.elems))
for i, elem := range l.elems {
elemVal := elem.Eval(ctx)
if types.IsUnknownOrError(elemVal) {
return 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)
}
func (l *evalList) InitVals() []Interpretable {
return l.elems
}
func (l *evalList) Type() ref.Type {
return types.ListType
}
type evalMap struct {
id int64
keys []Interpretable
vals []Interpretable
optionals []bool
hasOptionals bool
adapter types.Adapter
}
func (m *evalMap) ID() int64 {
return m.id
}
func (m *evalMap) Eval(ctx Activation) ref.Val {
entries := make(map[ref.Val]ref.Val)
for i, key := range m.keys {
keyVal := key.Eval(ctx)
if types.IsUnknownOrError(keyVal) {
return keyVal
}
valVal := m.vals[i].Eval(ctx)
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)
}
func (m *evalMap) InitVals() []Interpretable {
if len(m.keys) != len(m.vals) {
return nil
}
result := make([]Interpretable, len(m.keys)+len(m.vals))
idx := 0
for i, k := range m.keys {
v := m.vals[i]
result[idx] = k
idx++
result[idx] = v
idx++
}
return result
}
func (m *evalMap) Type() ref.Type {
return types.MapType
}
type evalObj struct {
id int64
typeName string
fields []string
vals []Interpretable
optionals []bool
hasOptionals bool
provider types.Provider
}
func (o *evalObj) ID() int64 {
return o.id
}
func (o *evalObj) Eval(ctx Activation) ref.Val {
fieldVals := make(map[string]ref.Val)
for i, field := range o.fields {
val := o.vals[i].Eval(ctx)
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)
}
func (o *evalObj) InitVals() []Interpretable {
return o.vals
}
func (o *evalObj) Type() ref.Type {
return types.NewObjectTypeValue(o.typeName)
}
type evalFold struct {
id int64
accuVar string
iterVar string
iterRange Interpretable
accu Interpretable
cond Interpretable
step Interpretable
result Interpretable
adapter types.Adapter
exhaustive bool
interruptable bool
}
func (fold *evalFold) ID() int64 {
return fold.id
}
func (fold *evalFold) Eval(ctx Activation) ref.Val {
foldRange := fold.iterRange.Eval(ctx)
if !foldRange.Type().HasTrait(traits.IterableType) {
return types.ValOrErr(foldRange, "got '%T', expected iterable type", foldRange)
}
accuCtx := varActivationPool.Get().(*varActivation)
accuCtx.parent = ctx
accuCtx.name = fold.accuVar
accuCtx.val = fold.accu.Eval(ctx)
l, ok := accuCtx.val.(traits.Lister)
buildingList := false
if !fold.exhaustive && ok && l.Size() == types.IntZero {
buildingList = true
accuCtx.val = types.NewMutableList(fold.adapter)
}
iterCtx := varActivationPool.Get().(*varActivation)
iterCtx.parent = accuCtx
iterCtx.name = fold.iterVar
interrupted := false
it := foldRange.(traits.Iterable).Iterator()
for it.HasNext() == types.True {
iterCtx.val = it.Next()
cond := fold.cond.Eval(iterCtx)
condBool, ok := cond.(types.Bool)
if !fold.exhaustive && ok && condBool != types.True {
break
}
accuCtx.val = fold.step.Eval(iterCtx)
if fold.interruptable {
if stop, found := ctx.ResolveName("#interrupted"); found && stop == true {
interrupted = true
break
}
}
}
varActivationPool.Put(iterCtx)
if interrupted {
varActivationPool.Put(accuCtx)
return types.NewErr("operation interrupted")
}
res := fold.result.Eval(accuCtx)
varActivationPool.Put(accuCtx)
if !types.IsUnknownOrError(res) && buildingList {
if _, ok := res.(traits.MutableLister); ok {
res = res.(traits.MutableLister).ToImmutableList()
}
}
return res
}
type evalSetMembership struct {
inst Interpretable
arg Interpretable
valueSet map[ref.Val]ref.Val
}
func (e *evalSetMembership) ID() int64 {
return e.inst.ID()
}
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
}
type evalWatch struct {
Interpretable
observer EvalObserver
}
func (e *evalWatch) Eval(ctx Activation) ref.Val {
val := e.Interpretable.Eval(ctx)
e.observer(e.ID(), e.Interpretable, val)
return val
}
type evalWatchAttr struct {
InterpretableAttribute
observer EvalObserver
}
func (e *evalWatchAttr) AddQualifier(q Qualifier) (Attribute, error) {
switch qual := q.(type) {
case ConstantQualifier:
q = &evalWatchConstQual{
ConstantQualifier: qual,
observer: e.observer,
adapter: e.Adapter(),
}
case *evalWatchAttr:
q = &evalWatchAttrQual{
Attribute: qual.InterpretableAttribute,
observer: e.observer,
adapter: e.Adapter(),
}
case Attribute:
q = &evalWatchAttrQual{
Attribute: qual,
observer: e.observer,
adapter: e.Adapter(),
}
default:
q = &evalWatchQual{
Qualifier: qual,
observer: e.observer,
adapter: e.Adapter(),
}
}
_, err := e.InterpretableAttribute.AddQualifier(q)
return e, err
}
func (e *evalWatchAttr) Eval(vars Activation) ref.Val {
val := e.InterpretableAttribute.Eval(vars)
e.observer(e.ID(), e.InterpretableAttribute, val)
return val
}
type evalWatchConstQual struct {
ConstantQualifier
observer EvalObserver
adapter types.Adapter
}
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.WrapErr(err)
} else {
val = e.adapter.NativeToValue(out)
}
e.observer(e.ID(), e.ConstantQualifier, val)
return out, err
}
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
}
func (e *evalWatchConstQual) QualifierValueEquals(value any) bool {
qve, ok := e.ConstantQualifier.(qualifierValueEquator)
return ok && qve.QualifierValueEquals(value)
}
type evalWatchAttrQual struct {
Attribute
observer EvalObserver
adapter ref.TypeAdapter
}
func (e *evalWatchAttrQual) Qualify(vars Activation, obj any) (any, error) {
out, err := e.Attribute.Qualify(vars, obj)
var val ref.Val
if err != nil {
val = types.WrapErr(err)
} else {
val = e.adapter.NativeToValue(out)
}
e.observer(e.ID(), e.Attribute, val)
return out, err
}
func (e *evalWatchAttrQual) QualifyIfPresent(vars Activation, obj any, presenceOnly bool) (any, bool, error) {
out, present, err := e.Attribute.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.Attribute, val)
}
return out, present, err
}
type evalWatchQual struct {
Qualifier
observer EvalObserver
adapter types.Adapter
}
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.WrapErr(err)
} else {
val = e.adapter.NativeToValue(out)
}
e.observer(e.ID(), e.Qualifier, val)
return out, err
}
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
}
type evalWatchConst struct {
InterpretableConst
observer EvalObserver
}
func (e *evalWatchConst) Eval(vars Activation) ref.Val {
val := e.Value()
e.observer(e.ID(), e.InterpretableConst, val)
return val
}
type evalExhaustiveOr struct {
id int64
terms []Interpretable
}
func (or *evalExhaustiveOr) ID() int64 {
return or.id
}
func (or *evalExhaustiveOr) Eval(ctx Activation) ref.Val {
var err ref.Val = nil
var unk *types.Unknown
isTrue := false
for _, term := range or.terms {
val := term.Eval(ctx)
boolVal, ok := val.(types.Bool)
if ok && boolVal == types.True {
isTrue = true
}
if !ok && !isTrue {
isUnk := false
unk, isUnk = types.MaybeMergeUnknowns(val, unk)
if !isUnk && err == nil {
if types.IsError(val) {
err = val
} else {
err = types.MaybeNoSuchOverloadErr(val)
}
}
}
}
if isTrue {
return types.True
}
if unk != nil {
return unk
}
if err != nil {
return err
}
return types.False
}
type evalExhaustiveAnd struct {
id int64
terms []Interpretable
}
func (and *evalExhaustiveAnd) ID() int64 {
return and.id
}
func (and *evalExhaustiveAnd) Eval(ctx Activation) ref.Val {
var err ref.Val = nil
var unk *types.Unknown
isFalse := false
for _, term := range and.terms {
val := term.Eval(ctx)
boolVal, ok := val.(types.Bool)
if ok && boolVal == types.False {
isFalse = true
}
if !ok && !isFalse {
isUnk := false
unk, isUnk = types.MaybeMergeUnknowns(val, unk)
if !isUnk && err == nil {
if types.IsError(val) {
err = val
} else {
err = types.MaybeNoSuchOverloadErr(val)
}
}
}
}
if isFalse {
return types.False
}
if unk != nil {
return unk
}
if err != nil {
return err
}
return types.True
}
type evalExhaustiveConditional struct {
id int64
adapter types.Adapter
attr *conditionalAttribute
}
func (cond *evalExhaustiveConditional) ID() int64 {
return cond.id
}
func (cond *evalExhaustiveConditional) Eval(ctx Activation) ref.Val {
cVal := cond.attr.expr.Eval(ctx)
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)
}
type evalAttr struct {
adapter types.Adapter
attr Attribute
optional bool
}
var _ InterpretableAttribute = &evalAttr{}
func (a *evalAttr) ID() int64 {
return a.attr.ID()
}
func (a *evalAttr) AddQualifier(qual Qualifier) (Attribute, error) {
attr, err := a.attr.AddQualifier(qual)
a.attr = attr
return attr, err
}
func (a *evalAttr) Attr() Attribute {
return a.attr
}
func (a *evalAttr) Adapter() types.Adapter {
return a.adapter
}
func (a *evalAttr) Eval(ctx Activation) ref.Val {
v, err := a.attr.Resolve(ctx)
if err != nil {
return types.WrapErr(err)
}
return a.adapter.NativeToValue(v)
}
func (a *evalAttr) Qualify(ctx Activation, obj any) (any, error) {
return a.attr.Qualify(ctx, obj)
}
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
}
func (a *evalAttr) Resolve(ctx Activation) (any, error) {
return a.attr.Resolve(ctx)
}
type evalWatchConstructor struct {
constructor InterpretableConstructor
observer EvalObserver
}
func (c *evalWatchConstructor) InitVals() []Interpretable {
return c.constructor.InitVals()
}
func (c *evalWatchConstructor) Type() ref.Type {
return c.constructor.Type()
}
func (c *evalWatchConstructor) ID() int64 {
return c.constructor.ID()
}
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)
}