engine, lang: Allow resources with a field of type interface

This lets us add a resource that has an implementation with a field
whose type is determined at compile time. This let's us write more
flexible resources.

What's missing is additional type checking so that we guarantee that a
specific resource doesn't change types during run-time.
This commit is contained in:
James Shubin
2023-11-12 16:16:47 -05:00
parent 9a1a81925e
commit b048b2684b
7 changed files with 62 additions and 1 deletions

View File

@@ -746,7 +746,13 @@ func (obj *StmtRes) resource(table map[interfaces.Func]types.Value, resName stri
if err != nil {
return nil, errwrap.Wrapf(err, "resource field `%s` has no compatible type", x.Field)
}
if err := t.Cmp(typ); err != nil {
if t == nil {
// possible programming error
return nil, fmt.Errorf("resource field `%s` of nil type cannot match type `%+v`", x.Field, typ)
}
// Let the variants pass through...
if err := t.Cmp(typ); err != nil && t.Kind != types.KindVariant {
return nil, errwrap.Wrapf(err, "resource field `%s` of type `%+v`, cannot take type `%+v`", x.Field, t, typ)
}
@@ -1320,6 +1326,29 @@ func (obj *StmtResField) Unify(kind string) ([]interfaces.Invariant, error) {
if !exists {
return nil, fmt.Errorf("field `%s` does not exist in `%s`", obj.Field, kind)
}
if typ == nil {
// possible programming error
return nil, fmt.Errorf("type for field `%s` in `%s` is nil", obj.Field, kind)
}
if typ.Kind == types.KindVariant { // special path, res field has interface{}
if typ.Var == nil {
invar := &interfaces.AnyInvariant{
Expr: obj.Value,
}
invariants = append(invariants, invar)
return invariants, nil
}
// in case it is present (nil is okay too)
invar := &interfaces.EqualsInvariant{
Expr: obj.Value,
Type: typ.Var, // in case it is present (nil is okay too)
}
invariants = append(invariants, invar)
return invariants, nil
}
// regular scenario
invar := &interfaces.EqualsInvariant{
Expr: obj.Value,
Type: typ,