From 4b76b751a5cb173d4776b530a3f58c8e851834a2 Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Wed, 20 Mar 2024 15:51:59 -0700 Subject: [PATCH] stdlib: Conversion functions can accept unknown-typed nulls This is one of those confusing situations where the multiple subtly-different meanings of cty.DynamicPseudoType meet: - The "Type" field specifies a target type that the argument must be converted to before calling the function, and so cty.DynamicPseudoType here essentially means "don't do any pre-conversion at all". - However, that means that the value given as an argument might be a null or unknown value with a type constraint. In that position, cty.DynamicPseudoType represents "we don't yet know the type", which not all functions are equipped to deal with and so those that are must opt-in with AllowDynamicPseudoType: true. Without declaring AllowDynamicPseudoType, the general function handling code will just skip calling the function at all when the argument doesn't yet have a known type, returning an unknown value of an unknown type to represent that the function's result cannot be known until the argument's type has become known. However, type conversion functions can safely accept values of unknown type, because they are just thin wrappers around package convert which already deal with that situation automatically. The conversion functions should set AllowDynamicType: true so that package convert can be the one to deal with the situation, and can thus convert a null value of unknown type into a null value of the target type (since null-to-null conversions are always allowed). --- CHANGELOG.md | 1 + cty/function/stdlib/conversion.go | 5 +++-- cty/function/stdlib/conversion_test.go | 6 ++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 96067e3a..f4c4426b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # 1.14.4 (Unreleased) * `msgpack`: Now uses string encoding instead of float encoding for a whole number that is too large to fit in any of MessagePack's integer types. +* `function/stdlib`: Type conversion functions (constructed with `MakeToFunc`) can now convert null values of unknown type into null values of the target type, rather than returning an unknown value in that case. # 1.14.3 (February 29, 2024) diff --git a/cty/function/stdlib/conversion.go b/cty/function/stdlib/conversion.go index 5d06a451..406dea23 100644 --- a/cty/function/stdlib/conversion.go +++ b/cty/function/stdlib/conversion.go @@ -30,8 +30,9 @@ func MakeToFunc(wantTy cty.Type) function.Function { // messages to be more appropriate for an explicit type // conversion, whereas the cty function system produces // messages aimed at _implicit_ type conversions. - Type: cty.DynamicPseudoType, - AllowNull: true, + Type: cty.DynamicPseudoType, + AllowNull: true, + AllowDynamicType: true, }, }, Type: func(args []cty.Value) (cty.Type, error) { diff --git a/cty/function/stdlib/conversion_test.go b/cty/function/stdlib/conversion_test.go index c25cec78..41796c83 100644 --- a/cty/function/stdlib/conversion_test.go +++ b/cty/function/stdlib/conversion_test.go @@ -56,6 +56,12 @@ func TestTo(t *testing.T) { cty.NullVal(cty.Number), ``, }, + { + cty.NullVal(cty.DynamicPseudoType), + cty.Number, + cty.NullVal(cty.Number), + ``, + }, { cty.UnknownVal(cty.Bool), cty.String,