You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Reflection has A Problem:
We want to support using `attr.Value`s inside of structs, slices, etc.
and just having the reflection package Do The Right Thing. This means
the reflection package needs to be able to create them.
We originally solved that in #30 by just instantiating empty values of
their type, and then calling a `SetTerraformValue` method on that value.
This was super annoying, because then we needed two methods for getting
an `attr.Value` set to the right values: `attr.Type.ValueFromTerraform`
and `attr.Value.SetTerraformValue` were basically the same thing. But
whatever, it worked.
Except, no it didn't.
Complex types like lists and maps store their element/attribute types as
properties on their structs. It's important that these be set. Only the
`attr.Type` has this information, it's not passed in as part of the
`tftypes.Value`. So reflect couldn't set those values, and produced
broken `attr.Value`s as a result. (Their `ToTerraformValue` methods
would run into trouble, because they wouldn't know what `tftypes.Type`
to use for elements or attributes).
To solve this problem, we decided to supply the `attr.Type` from the
schema to the reflect package, wiring it through so that we could
instantiate new `attr.Value`s when the opportunity presented itself.
This solves our problem, because we got rid of the
`attr.Value.SetTerraformValue` method and used the
`attr.Type.ValueFromTerraform` directly to just instantiate a new value,
which made sure it was set up correctly. But now we have a new problem:
what if the `attr.Type` in the schema doesn't produce the `attr.Value`
they're trying to assign to? We decided to just throw an error on that
one, because there's no reasonable way around it.
Depends on #44.
returntarget, path.NewErrorf("unexpectedly couldn't find SetTeraformValue method on type %s", receiver.Type().String())
75
-
}
76
-
results:=method.Call([]reflect.Value{
77
-
reflect.ValueOf(ctx),
78
-
reflect.ValueOf(val),
79
-
})
80
-
err:=results[0].Interface()
83
+
// AttributeValue creates a new reflect.Value by calling the ValueFromTerraform
84
+
// method on `typ`. It will return an error if the returned `attr.Value` is not
85
+
// the same type as `target`.
86
+
//
87
+
// It is meant to be called through Into, not directly.
88
+
funcAttributeValue(ctx context.Context, typ attr.Type, val tftypes.Value, target reflect.Value, optsOptions, path*tftypes.AttributePath) (reflect.Value, error) {
89
+
res, err:=typ.ValueFromTerraform(ctx, val)
81
90
iferr!=nil {
82
-
returntarget, path.NewError(err.(error))
91
+
returntarget, err
83
92
}
84
-
returnreceiver, nil
93
+
ifreflect.TypeOf(res) !=target.Type() {
94
+
returntarget, path.NewErrorf("can't use attr.Value %s, only %s is supported because %T is the type in the schema", target.Type(), reflect.TypeOf(res), typ)
0 commit comments