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
The json.ImpliedType function is a helper to infer a cty.Type that a given JSON payload ought to be able to decode into without loss. This is intended for situations where applications are accepting arbitrary JSON without any fixed type/schema in mind, and an example in this codebase is the function/stdlib implementation of JSONDecode:
The ImpliedType implementation deals with objects on a property-by-property basis, with the intend of finding the full set of attribute names that are included in the object and a suitable type constraint to use for each one:
returncty.NilType, fmt.Errorf("expected string but found %T", tok)
}
// Now read the value
tok, err=dec.Token()
iferr!=nil {
returncty.NilType, err
}
aty, err:=impliedTypeForTok(tok, dec)
iferr!=nil {
returncty.NilType, err
}
ifatys==nil {
atys=make(map[string]cty.Type)
}
atys[key] =aty
}
iflen(atys) ==0 {
returncty.EmptyObject, nil
}
returncty.Object(atys), nil
Currently this loop doesn't check whether atys already contains an element for the given key, which means that a JSON object with two properties that have the same name is considered to imply a type that expects that attribute to be of the type of whatever was the final occurrence of that property name in a given object.
For example, given this input:
{
"a": "hello",
"a": true
}
The result would be cty.Object(map[string]cty.Type{"a": cty.Bool}).
A subsequent attempt to translate that input into a cty.Value using json.Unmarshal with that returned type would fail, because it would try to convert "hello" from the first "a" to a cty.Bool, which is impossible.
The ImpliedType function should probably have just immediately rejected duplicate property names, because although they are technically valid in JSON syntax, they have unspecified meaning and for the purposes of json.ImpliedType and json.Unmarshal they can't really have any significant meaning due to the constraints of cty's own definition of object types.
However, it is technically possible today to provide an object with duplicate properties that are all of the same type and have that "work" in some sense:
{
"a": "hello",
"a": "world"
}
The implied type is cty.Object(map[string]cty.Type{"a": cty.String}). and the Unmarshal function is also happy to first convert "hello" to string, then convert "world" to string to replace it, thereby returning cty.ObjectVal(map[string]cty.Value{"a": cty.StringVal("world")}) with no errors.
Given that, to preserve the current valid case (even though it's dubious whether that valid result is actually useful) I think the new behavior should be for json.ImpliedType to return an error if it finds two properties of the same name of incompatible types, but to continue to accept duplicates if their types are compatible. That therefore would narrowly introduce a better error message for the case that can't work without breaking the case that does currently work.
(It is technically still "breaking" of an application that was expecting to be able to json.ImpliedType successfully without subsequently calling json.Unmarshal, since the error only appears when both are combined as in our stdlib.JSONDecode function, but that particular scenario seems marginal enough that I think it's worth breaking it to improve the messaging for the more likely situation.)
The text was updated successfully, but these errors were encountered:
The
json.ImpliedType
function is a helper to infer acty.Type
that a given JSON payload ought to be able to decode into without loss. This is intended for situations where applications are accepting arbitrary JSON without any fixed type/schema in mind, and an example in this codebase is thefunction/stdlib
implementation ofJSONDecode
:go-cty/cty/function/stdlib/json.go
Lines 123 to 124 in 0ed0ebb
The
ImpliedType
implementation deals with objects on a property-by-property basis, with the intend of finding the full set of attribute names that are included in the object and a suitable type constraint to use for each one:go-cty/cty/json/type_implied.go
Lines 95 to 137 in 0ed0ebb
Currently this loop doesn't check whether
atys
already contains an element for the givenkey
, which means that a JSON object with two properties that have the same name is considered to imply a type that expects that attribute to be of the type of whatever was the final occurrence of that property name in a given object.For example, given this input:
The result would be
cty.Object(map[string]cty.Type{"a": cty.Bool})
.A subsequent attempt to translate that input into a
cty.Value
usingjson.Unmarshal
with that returned type would fail, because it would try to convert"hello"
from the first"a"
to acty.Bool
, which is impossible.The
ImpliedType
function should probably have just immediately rejected duplicate property names, because although they are technically valid in JSON syntax, they have unspecified meaning and for the purposes ofjson.ImpliedType
andjson.Unmarshal
they can't really have any significant meaning due to the constraints ofcty
's own definition of object types.However, it is technically possible today to provide an object with duplicate properties that are all of the same type and have that "work" in some sense:
The implied type is
cty.Object(map[string]cty.Type{"a": cty.String})
. and theUnmarshal
function is also happy to first convert"hello"
to string, then convert"world"
to string to replace it, thereby returningcty.ObjectVal(map[string]cty.Value{"a": cty.StringVal("world")})
with no errors.Given that, to preserve the current valid case (even though it's dubious whether that valid result is actually useful) I think the new behavior should be for
json.ImpliedType
to return an error if it finds two properties of the same name of incompatible types, but to continue to accept duplicates if their types are compatible. That therefore would narrowly introduce a better error message for the case that can't work without breaking the case that does currently work.(It is technically still "breaking" of an application that was expecting to be able to
json.ImpliedType
successfully without subsequently callingjson.Unmarshal
, since the error only appears when both are combined as in ourstdlib.JSONDecode
function, but that particular scenario seems marginal enough that I think it's worth breaking it to improve the messaging for the more likely situation.)The text was updated successfully, but these errors were encountered: