From eae77b661ae6aac58242defb14246b30c8fdf01d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Jan 2022 19:06:19 +0000 Subject: [PATCH] Bump github.com/zclconf/go-cty from 1.8.1 to 1.10.0 Bumps [github.com/zclconf/go-cty](https://github.com/zclconf/go-cty) from 1.8.1 to 1.10.0. - [Release notes](https://github.com/zclconf/go-cty/releases) - [Changelog](https://github.com/zclconf/go-cty/blob/main/CHANGELOG.md) - [Commits](https://github.com/zclconf/go-cty/compare/v1.8.1...v1.10.0) --- updated-dependencies: - dependency-name: github.com/zclconf/go-cty dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 +- .../go-cty/cty/function/stdlib/collection.go | 310 ++++++++++++------ .../zclconf/go-cty/cty/function/stdlib/csv.go | 13 +- .../go-cty/cty/function/stdlib/format.go | 2 + .../go-cty/cty/function/stdlib/number.go | 38 ++- .../go-cty/cty/function/stdlib/sequence.go | 27 +- vendor/github.com/zclconf/go-cty/cty/marks.go | 21 ++ .../zclconf/go-cty/cty/primitive_type.go | 45 +++ .../zclconf/go-cty/cty/value_ops.go | 27 +- vendor/github.com/zclconf/go-cty/cty/walk.go | 35 +- vendor/modules.txt | 2 +- 12 files changed, 381 insertions(+), 145 deletions(-) diff --git a/go.mod b/go.mod index 9d5ca8f..285697e 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,6 @@ require ( github.com/hashicorp/hcl/v2 v2.10.0 github.com/hashicorp/terraform v0.14.10 github.com/stretchr/testify v1.7.0 - github.com/zclconf/go-cty v1.8.1 + github.com/zclconf/go-cty v1.10.0 github.com/zclconf/go-cty-yaml v1.0.2 ) diff --git a/go.sum b/go.sum index 672b2a0..db6220e 100644 --- a/go.sum +++ b/go.sum @@ -400,8 +400,8 @@ github.com/zclconf/go-cty v1.0.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLE github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s= github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= -github.com/zclconf/go-cty v1.8.1 h1:SI0LqNeNxAgv2WWqWJMlG2/Ad/6aYJ7IVYYMigmfkuI= -github.com/zclconf/go-cty v1.8.1/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= +github.com/zclconf/go-cty v1.10.0 h1:mp9ZXQeIcN8kAwuqorjH+Q+njbJKjLrvB2yIh4q7U+0= +github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= github.com/zclconf/go-cty-yaml v1.0.2 h1:dNyg4QLTrv2IfJpm7Wtxi55ed5gLGOlPrZ6kMd51hY0= github.com/zclconf/go-cty-yaml v1.0.2/go.mod h1:IP3Ylp0wQpYm50IHK8OZWKMu6sPJIUgKa8XhiVHura0= diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/collection.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/collection.go index 230b03a..279a20e 100644 --- a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/collection.go +++ b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/collection.go @@ -111,6 +111,7 @@ var LengthFunc = function.New(&function.Spec{ Name: "collection", Type: cty.DynamicPseudoType, AllowDynamicType: true, + AllowMarked: true, }, }, Type: func(args []cty.Value) (ret cty.Type, err error) { @@ -128,8 +129,9 @@ var LengthFunc = function.New(&function.Spec{ var ElementFunc = function.New(&function.Spec{ Params: []function.Parameter{ { - Name: "list", - Type: cty.DynamicPseudoType, + Name: "list", + Type: cty.DynamicPseudoType, + AllowMarked: true, }, { Name: "index", @@ -184,11 +186,12 @@ var ElementFunc = function.New(&function.Spec{ return cty.DynamicVal, fmt.Errorf("cannot use element function with a negative index") } - if !args[0].IsKnown() { + input, marks := args[0].Unmark() + if !input.IsKnown() { return cty.UnknownVal(retType), nil } - l := args[0].LengthInt() + l := input.LengthInt() if l == 0 { return cty.DynamicVal, errors.New("cannot use element function with an empty list") } @@ -196,7 +199,7 @@ var ElementFunc = function.New(&function.Spec{ // We did all the necessary type checks in the type function above, // so this is guaranteed not to fail. - return args[0].Index(cty.NumberIntVal(int64(index))), nil + return input.Index(cty.NumberIntVal(int64(index))).WithMarks(marks), nil }, }) @@ -398,12 +401,14 @@ var DistinctFunc = function.New(&function.Spec{ var ChunklistFunc = function.New(&function.Spec{ Params: []function.Parameter{ { - Name: "list", - Type: cty.List(cty.DynamicPseudoType), + Name: "list", + Type: cty.List(cty.DynamicPseudoType), + AllowMarked: true, }, { - Name: "size", - Type: cty.Number, + Name: "size", + Type: cty.Number, + AllowMarked: true, }, }, Type: func(args []cty.Value) (cty.Type, error) { @@ -411,35 +416,40 @@ var ChunklistFunc = function.New(&function.Spec{ }, Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { listVal := args[0] - if !listVal.IsKnown() { - return cty.UnknownVal(retType), nil - } - - if listVal.LengthInt() == 0 { - return cty.ListValEmpty(listVal.Type()), nil - } + sizeVal := args[1] + listVal, listMarks := listVal.Unmark() + sizeVal, sizeMarks := sizeVal.Unmark() + // All return paths below must include .WithMarks(retMarks) to propagate + // the top-level marks into the return value. Deep marks inside the + // list will just propagate naturally because we treat those values + // as opaque here. + retMarks := cty.NewValueMarks(listMarks, sizeMarks) var size int - err = gocty.FromCtyValue(args[1], &size) + err = gocty.FromCtyValue(sizeVal, &size) if err != nil { - return cty.NilVal, fmt.Errorf("invalid index: %s", err) + return cty.NilVal, fmt.Errorf("invalid size: %s", err) } if size < 0 { return cty.NilVal, errors.New("the size argument must be positive") } + if listVal.LengthInt() == 0 { + return cty.ListValEmpty(listVal.Type()).WithMarks(retMarks), nil + } + output := make([]cty.Value, 0) // if size is 0, returns a list made of the initial list if size == 0 { output = append(output, listVal) - return cty.ListVal(output), nil + return cty.ListVal(output).WithMarks(retMarks), nil } chunk := make([]cty.Value, 0) - l := args[0].LengthInt() + l := listVal.LengthInt() i := 0 for it := listVal.ElementIterator(); it.Next(); { @@ -454,7 +464,7 @@ var ChunklistFunc = function.New(&function.Spec{ i++ } - return cty.ListVal(output), nil + return cty.ListVal(output).WithMarks(retMarks), nil }, }) @@ -463,8 +473,9 @@ var ChunklistFunc = function.New(&function.Spec{ var FlattenFunc = function.New(&function.Spec{ Params: []function.Parameter{ { - Name: "list", - Type: cty.DynamicPseudoType, + Name: "list", + Type: cty.DynamicPseudoType, + AllowMarked: true, }, }, Type: func(args []cty.Value) (cty.Type, error) { @@ -477,7 +488,8 @@ var FlattenFunc = function.New(&function.Spec{ return cty.NilType, errors.New("can only flatten lists, sets and tuples") } - retVal, known := flattener(args[0]) + // marks are attached to values, so ignore while determining type + retVal, _, known := flattener(args[0]) if !known { return cty.DynamicPseudoType, nil } @@ -490,46 +502,66 @@ var FlattenFunc = function.New(&function.Spec{ }, Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { inputList := args[0] - if inputList.LengthInt() == 0 { - return cty.EmptyTupleVal, nil + + if unmarked, marks := inputList.Unmark(); unmarked.LengthInt() == 0 { + return cty.EmptyTupleVal.WithMarks(marks), nil } - out, known := flattener(inputList) + out, markses, known := flattener(inputList) if !known { - return cty.UnknownVal(retType), nil + return cty.UnknownVal(retType).WithMarks(markses...), nil } - return cty.TupleVal(out), nil + return cty.TupleVal(out).WithMarks(markses...), nil }, }) // Flatten until it's not a cty.List, and return whether the value is known. // We can flatten lists with unknown values, as long as they are not // lists themselves. -func flattener(flattenList cty.Value) ([]cty.Value, bool) { +func flattener(flattenList cty.Value) ([]cty.Value, []cty.ValueMarks, bool) { + var markses []cty.ValueMarks + flattenList, flattenListMarks := flattenList.Unmark() + if len(flattenListMarks) > 0 { + markses = append(markses, flattenListMarks) + } if !flattenList.Length().IsKnown() { // If we don't know the length of what we're flattening then we can't // predict the length of our result yet either. - return nil, false + return nil, markses, false } + out := make([]cty.Value, 0) + isKnown := true for it := flattenList.ElementIterator(); it.Next(); { _, val := it.Element() + + // Any dynamic types could result in more collections that need to be + // flattened, so the type cannot be known. + if val == cty.DynamicVal { + isKnown = false + } + if val.Type().IsListType() || val.Type().IsSetType() || val.Type().IsTupleType() { if !val.IsKnown() { - return out, false + isKnown = false + _, unknownMarks := val.Unmark() + markses = append(markses, unknownMarks) + continue } - res, known := flattener(val) - if !known { - return res, known + res, resMarks, known := flattener(val) + markses = append(markses, resMarks...) + if known { + out = append(out, res...) + } else { + isKnown = false } - out = append(out, res...) } else { out = append(out, val) } } - return out, true + return out, markses, isKnown } // KeysFunc is a function that takes a map and returns a sorted list of the map keys. @@ -539,6 +571,7 @@ var KeysFunc = function.New(&function.Spec{ Name: "inputMap", Type: cty.DynamicPseudoType, AllowUnknown: true, + AllowMarked: true, }, }, Type: func(args []cty.Value) (cty.Type, error) { @@ -563,7 +596,11 @@ var KeysFunc = function.New(&function.Spec{ } }, Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - m := args[0] + // We must unmark the value before we can use ElementIterator on it, and + // then re-apply the same marks (possibly none) when we return. Since we + // don't mark map keys, we can throw away any nested marks, which would + // only apply to values. + m, marks := args[0].Unmark() var keys []cty.Value switch { @@ -576,28 +613,28 @@ var KeysFunc = function.New(&function.Spec{ } sort.Strings(names) // same ordering guaranteed by cty's ElementIterator if len(names) == 0 { - return cty.EmptyTupleVal, nil + return cty.EmptyTupleVal.WithMarks(marks), nil } keys = make([]cty.Value, len(names)) for i, name := range names { keys[i] = cty.StringVal(name) } - return cty.TupleVal(keys), nil + return cty.TupleVal(keys).WithMarks(marks), nil default: if !m.IsKnown() { - return cty.UnknownVal(retType), nil + return cty.UnknownVal(retType).WithMarks(marks), nil } // cty guarantees that ElementIterator will iterate in lexicographical // order by key. - for it := args[0].ElementIterator(); it.Next(); { + for it := m.ElementIterator(); it.Next(); { k, _ := it.Element() keys = append(keys, k) } if len(keys) == 0 { - return cty.ListValEmpty(cty.String), nil + return cty.ListValEmpty(cty.String).WithMarks(marks), nil } - return cty.ListVal(keys), nil + return cty.ListVal(keys).WithMarks(marks), nil } }, }) @@ -606,16 +643,19 @@ var KeysFunc = function.New(&function.Spec{ var LookupFunc = function.New(&function.Spec{ Params: []function.Parameter{ { - Name: "inputMap", - Type: cty.DynamicPseudoType, + Name: "inputMap", + Type: cty.DynamicPseudoType, + AllowMarked: true, }, { - Name: "key", - Type: cty.String, + Name: "key", + Type: cty.String, + AllowMarked: true, }, { - Name: "default", - Type: cty.DynamicPseudoType, + Name: "default", + Type: cty.DynamicPseudoType, + AllowMarked: true, }, }, Type: func(args []cty.Value) (ret cty.Type, err error) { @@ -627,7 +667,8 @@ var LookupFunc = function.New(&function.Spec{ return cty.DynamicPseudoType, nil } - key := args[1].AsString() + keyVal, _ := args[1].Unmark() + key := keyVal.AsString() if ty.HasAttribute(key) { return args[0].GetAttr(key).Type(), nil } else if len(args) == 3 { @@ -649,28 +690,39 @@ var LookupFunc = function.New(&function.Spec{ } }, Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { + // leave default value marked defaultVal := args[2] - mapVar := args[0] - lookupKey := args[1].AsString() + var markses []cty.ValueMarks + + // unmark collection, retain marks to reapply later + mapVar, mapMarks := args[0].Unmark() + markses = append(markses, mapMarks) + + // include marks on the key in the result + keyVal, keyMarks := args[1].Unmark() + if len(keyMarks) > 0 { + markses = append(markses, keyMarks) + } + lookupKey := keyVal.AsString() if !mapVar.IsWhollyKnown() { - return cty.UnknownVal(retType), nil + return cty.UnknownVal(retType).WithMarks(markses...), nil } if mapVar.Type().IsObjectType() { if mapVar.Type().HasAttribute(lookupKey) { - return mapVar.GetAttr(lookupKey), nil + return mapVar.GetAttr(lookupKey).WithMarks(markses...), nil } } else if mapVar.HasIndex(cty.StringVal(lookupKey)) == cty.True { - return mapVar.Index(cty.StringVal(lookupKey)), nil + return mapVar.Index(cty.StringVal(lookupKey)).WithMarks(markses...), nil } defaultVal, err = convert.Convert(defaultVal, retType) if err != nil { return cty.NilVal, err } - return defaultVal, nil + return defaultVal.WithMarks(markses...), nil }, }) @@ -687,6 +739,7 @@ var MergeFunc = function.New(&function.Spec{ Type: cty.DynamicPseudoType, AllowDynamicType: true, AllowNull: true, + AllowMarked: true, }, Type: func(args []cty.Value) (cty.Type, error) { // empty args is accepted, so assume an empty object since we have no @@ -712,6 +765,8 @@ var MergeFunc = function.New(&function.Spec{ if !ty.IsMapType() && !ty.IsObjectType() { return cty.NilType, fmt.Errorf("arguments must be maps or objects, got %#v", ty.FriendlyName()) } + // marks are attached to values, so ignore while determining type + arg, _ = arg.Unmark() switch { case ty.IsObjectType() && !arg.IsNull(): @@ -761,11 +816,16 @@ var MergeFunc = function.New(&function.Spec{ }, Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { outputMap := make(map[string]cty.Value) + var markses []cty.ValueMarks // remember any marked maps/objects we find for _, arg := range args { if arg.IsNull() { continue } + arg, argMarks := arg.Unmark() + if len(argMarks) > 0 { + markses = append(markses, argMarks) + } for it := arg.ElementIterator(); it.Next(); { k, v := it.Element() outputMap[k.AsString()] = v @@ -775,11 +835,11 @@ var MergeFunc = function.New(&function.Spec{ switch { case retType.IsMapType(): if len(outputMap) == 0 { - return cty.MapValEmpty(retType.ElementType()), nil + return cty.MapValEmpty(retType.ElementType()).WithMarks(markses...), nil } - return cty.MapVal(outputMap), nil + return cty.MapVal(outputMap).WithMarks(markses...), nil case retType.IsObjectType(), retType.Equals(cty.DynamicPseudoType): - return cty.ObjectVal(outputMap), nil + return cty.ObjectVal(outputMap).WithMarks(markses...), nil default: panic(fmt.Sprintf("unexpected return type: %#v", retType)) } @@ -791,8 +851,9 @@ var MergeFunc = function.New(&function.Spec{ var ReverseListFunc = function.New(&function.Spec{ Params: []function.Parameter{ { - Name: "list", - Type: cty.DynamicPseudoType, + Name: "list", + Type: cty.DynamicPseudoType, + AllowMarked: true, }, }, Type: func(args []cty.Value) (cty.Type, error) { @@ -812,19 +873,21 @@ var ReverseListFunc = function.New(&function.Spec{ } }, Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - in := args[0].AsValueSlice() - outVals := make([]cty.Value, len(in)) - for i, v := range in { + in, marks := args[0].Unmark() + inVals := in.AsValueSlice() + outVals := make([]cty.Value, len(inVals)) + + for i, v := range inVals { outVals[len(outVals)-i-1] = v } switch { case retType.IsTupleType(): - return cty.TupleVal(outVals), nil + return cty.TupleVal(outVals).WithMarks(marks), nil default: if len(outVals) == 0 { - return cty.ListValEmpty(retType.ElementType()), nil + return cty.ListValEmpty(retType.ElementType()).WithMarks(marks), nil } - return cty.ListVal(outVals), nil + return cty.ListVal(outVals).WithMarks(marks), nil } }, }) @@ -836,8 +899,9 @@ var ReverseListFunc = function.New(&function.Spec{ var SetProductFunc = function.New(&function.Spec{ Params: []function.Parameter{}, VarParam: &function.Parameter{ - Name: "sets", - Type: cty.DynamicPseudoType, + Name: "sets", + Type: cty.DynamicPseudoType, + AllowMarked: true, }, Type: func(args []cty.Value) (retType cty.Type, err error) { if len(args) < 2 { @@ -881,11 +945,19 @@ var SetProductFunc = function.New(&function.Spec{ }, Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { ety := retType.ElementType() + var retMarks cty.ValueMarks total := 1 + var hasUnknownLength bool for _, arg := range args { + arg, marks := arg.Unmark() + retMarks = cty.NewValueMarks(retMarks, marks) + + // Continue processing after we find an argument with unknown + // length to ensure that we cover all the marks if !arg.Length().IsKnown() { - return cty.UnknownVal(retType), nil + hasUnknownLength = true + continue } // Because of our type checking function, we are guaranteed that @@ -894,13 +966,17 @@ var SetProductFunc = function.New(&function.Spec{ total *= arg.LengthInt() } + if hasUnknownLength { + return cty.UnknownVal(retType).WithMarks(retMarks), nil + } + if total == 0 { // If any of the arguments was an empty collection then our result // is also an empty collection, which we'll short-circuit here. if retType.IsListType() { - return cty.ListValEmpty(ety), nil + return cty.ListValEmpty(ety).WithMarks(retMarks), nil } - return cty.SetValEmpty(ety), nil + return cty.SetValEmpty(ety).WithMarks(retMarks), nil } subEtys := ety.TupleElementTypes() @@ -911,6 +987,8 @@ var SetProductFunc = function.New(&function.Spec{ s := 0 argVals := make([][]cty.Value, len(args)) for i, arg := range args { + // We've already stored the marks in retMarks + arg, _ := arg.Unmark() argVals[i] = arg.AsValueSlice() } @@ -950,9 +1028,9 @@ var SetProductFunc = function.New(&function.Spec{ } if retType.IsListType() { - return cty.ListVal(productVals), nil + return cty.ListVal(productVals).WithMarks(retMarks), nil } - return cty.SetVal(productVals), nil + return cty.SetVal(productVals).WithMarks(retMarks), nil }, }) @@ -961,8 +1039,9 @@ var SetProductFunc = function.New(&function.Spec{ var SliceFunc = function.New(&function.Spec{ Params: []function.Parameter{ { - Name: "list", - Type: cty.DynamicPseudoType, + Name: "list", + Type: cty.DynamicPseudoType, + AllowMarked: true, }, { Name: "start_index", @@ -1001,10 +1080,10 @@ var SliceFunc = function.New(&function.Spec{ return cty.Tuple(argTy.TupleElementTypes()[startIndex:endIndex]), nil }, Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - inputList := args[0] + inputList, marks := args[0].Unmark() if retType == cty.DynamicPseudoType { - return cty.DynamicVal, nil + return cty.DynamicVal.WithMarks(marks), nil } // we ignore idxsKnown return value here because the indices are always @@ -1016,18 +1095,18 @@ var SliceFunc = function.New(&function.Spec{ if endIndex-startIndex == 0 { if retType.IsTupleType() { - return cty.EmptyTupleVal, nil + return cty.EmptyTupleVal.WithMarks(marks), nil } - return cty.ListValEmpty(retType.ElementType()), nil + return cty.ListValEmpty(retType.ElementType()).WithMarks(marks), nil } outputList := inputList.AsValueSlice()[startIndex:endIndex] if retType.IsTupleType() { - return cty.TupleVal(outputList), nil + return cty.TupleVal(outputList).WithMarks(marks), nil } - return cty.ListVal(outputList), nil + return cty.ListVal(outputList).WithMarks(marks), nil }, }) @@ -1035,9 +1114,12 @@ func sliceIndexes(args []cty.Value) (int, int, bool, error) { var startIndex, endIndex, length int var startKnown, endKnown, lengthKnown bool + // remove marks from args[0] + list, _ := args[0].Unmark() + // If it's a tuple then we always know the length by the type, but collections might be unknown or have unknown length - if args[0].Type().IsTupleType() || args[0].Length().IsKnown() { - length = args[0].LengthInt() + if list.Type().IsTupleType() || list.Length().IsKnown() { + length = list.LengthInt() lengthKnown = true } @@ -1078,8 +1160,9 @@ func sliceIndexes(args []cty.Value) (int, int, bool, error) { var ValuesFunc = function.New(&function.Spec{ Params: []function.Parameter{ { - Name: "values", - Type: cty.DynamicPseudoType, + Name: "values", + Type: cty.DynamicPseudoType, + AllowMarked: true, }, }, Type: func(args []cty.Value) (ret cty.Type, err error) { @@ -1112,6 +1195,13 @@ var ValuesFunc = function.New(&function.Spec{ Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { mapVar := args[0] + // We must unmark the value before we can use ElementIterator on it, + // and then re-apply the same marks (possibly none) when we return. + // (We leave the inner values just as they are, because we won't be + // doing anything with them aside from copying them verbatim into the + // result, marks and all.) + mapVar, marks := mapVar.Unmark() + // We can just iterate the map/object value here because cty guarantees // that these types always iterate in key lexicographical order. var values []cty.Value @@ -1120,13 +1210,15 @@ var ValuesFunc = function.New(&function.Spec{ values = append(values, val) } + // All of the return paths must include .WithMarks(marks) so that we + // will preserve the markings of the overall map/object we were given. if retType.IsTupleType() { - return cty.TupleVal(values), nil + return cty.TupleVal(values).WithMarks(marks), nil } if len(values) == 0 { - return cty.ListValEmpty(retType.ElementType()), nil + return cty.ListValEmpty(retType.ElementType()).WithMarks(marks), nil } - return cty.ListVal(values), nil + return cty.ListVal(values).WithMarks(marks), nil }, }) @@ -1135,12 +1227,14 @@ var ValuesFunc = function.New(&function.Spec{ var ZipmapFunc = function.New(&function.Spec{ Params: []function.Parameter{ { - Name: "keys", - Type: cty.List(cty.String), + Name: "keys", + Type: cty.List(cty.String), + AllowMarked: true, }, { - Name: "values", - Type: cty.DynamicPseudoType, + Name: "values", + Type: cty.DynamicPseudoType, + AllowMarked: true, }, }, Type: func(args []cty.Value) (ret cty.Type, err error) { @@ -1158,6 +1252,13 @@ var ZipmapFunc = function.New(&function.Spec{ return cty.DynamicPseudoType, nil } + // NOTE: Marking of the keys list can't be represented in the + // result type, so the tuple type here will disclose the keys. + // This is unfortunate but is a common compromise with dynamic + // return types; the result from Impl will still reflect the marks + // from the keys list, so a mark-using caller should look out for + // that if it's important for their use-case. + keys, _ := keys.Unmark() keysRaw := keys.AsValueSlice() valueTypesRaw := valuesTy.TupleElementTypes() if len(keysRaw) != len(valueTypesRaw) { @@ -1165,6 +1266,7 @@ var ZipmapFunc = function.New(&function.Spec{ } atys := make(map[string]cty.Type, len(valueTypesRaw)) for i, keyVal := range keysRaw { + keyVal, _ = keyVal.Unmark() if keyVal.IsNull() { return cty.NilType, fmt.Errorf("keys list has null value at index %d", i) } @@ -1180,11 +1282,17 @@ var ZipmapFunc = function.New(&function.Spec{ Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { keys := args[0] values := args[1] + keys, keysMarks := keys.Unmark() + values, valuesMarks := values.Unmark() + + // All of our return paths must pass through the merged marks from + // both the keys and the values, if any, using .WithMarks(retMarks) + retMarks := cty.NewValueMarks(keysMarks, valuesMarks) if !keys.IsWhollyKnown() { // Unknown map keys and object attributes are not supported, so // our entire result must be unknown in this case. - return cty.UnknownVal(retType), nil + return cty.UnknownVal(retType).WithMarks(retMarks), nil } // both keys and values are guaranteed to be shallowly-known here, @@ -1198,19 +1306,25 @@ var ZipmapFunc = function.New(&function.Spec{ i := 0 for it := keys.ElementIterator(); it.Next(); { _, v := it.Element() + v, vMarks := v.Unmark() val := values.Index(cty.NumberIntVal(int64(i))) output[v.AsString()] = val + + // We also need to accumulate the individual key marks on the + // returned map, because keys can't carry marks on their own. + retMarks = cty.NewValueMarks(retMarks, vMarks) + i++ } switch { case retType.IsMapType(): if len(output) == 0 { - return cty.MapValEmpty(retType.ElementType()), nil + return cty.MapValEmpty(retType.ElementType()).WithMarks(retMarks), nil } - return cty.MapVal(output), nil + return cty.MapVal(output).WithMarks(retMarks), nil case retType.IsObjectType(): - return cty.ObjectVal(output), nil + return cty.ObjectVal(output).WithMarks(retMarks), nil default: // Should never happen because the type-check function should've // caught any other case. diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/csv.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/csv.go index 5070a5a..339d04d 100644 --- a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/csv.go +++ b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/csv.go @@ -30,7 +30,7 @@ var CSVDecodeFunc = function.New(&function.Spec{ return cty.DynamicPseudoType, fmt.Errorf("missing header line") } if err != nil { - return cty.DynamicPseudoType, err + return cty.DynamicPseudoType, csvError(err) } atys := make(map[string]cty.Type, len(headers)) @@ -64,7 +64,7 @@ var CSVDecodeFunc = function.New(&function.Spec{ break } if err != nil { - return cty.DynamicVal, err + return cty.DynamicVal, csvError(err) } vals := make(map[string]cty.Value, len(cols)) @@ -91,3 +91,12 @@ var CSVDecodeFunc = function.New(&function.Spec{ func CSVDecode(str cty.Value) (cty.Value, error) { return CSVDecodeFunc.Call([]cty.Value{str}) } + +func csvError(err error) error { + switch err := err.(type) { + case *csv.ParseError: + return fmt.Errorf("CSV parse error on line %d: %w", err.Line, err.Err) + default: + return err + } +} diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format.go index 63881f5..8b17758 100644 --- a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format.go +++ b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format.go @@ -114,6 +114,8 @@ var FormatListFunc = function.New(&function.Spec{ continue } iterators[i] = arg.ElementIterator() + case arg == cty.DynamicVal: + unknowns[i] = true default: singleVals[i] = arg } diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/number.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/number.go index 7bbe584..4effeb7 100644 --- a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/number.go +++ b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/number.go @@ -371,14 +371,21 @@ var CeilFunc = function.New(&function.Spec{ }, Type: function.StaticReturnType(cty.Number), Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - var val float64 - if err := gocty.FromCtyValue(args[0], &val); err != nil { - return cty.UnknownVal(cty.String), err + f := args[0].AsBigFloat() + + if f.IsInf() { + return cty.NumberVal(f), nil } - if math.IsInf(val, 0) { - return cty.NumberFloatVal(val), nil + + i, acc := f.Int(nil) + switch acc { + case big.Exact, big.Above: + // Done. + case big.Below: + i.Add(i, big.NewInt(1)) } - return cty.NumberIntVal(int64(math.Ceil(val))), nil + + return cty.NumberVal(f.SetInt(i)), nil }, }) @@ -393,14 +400,21 @@ var FloorFunc = function.New(&function.Spec{ }, Type: function.StaticReturnType(cty.Number), Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - var val float64 - if err := gocty.FromCtyValue(args[0], &val); err != nil { - return cty.UnknownVal(cty.String), err + f := args[0].AsBigFloat() + + if f.IsInf() { + return cty.NumberVal(f), nil } - if math.IsInf(val, 0) { - return cty.NumberFloatVal(val), nil + + i, acc := f.Int(nil) + switch acc { + case big.Exact, big.Below: + // Done. + case big.Above: + i.Sub(i, big.NewInt(1)) } - return cty.NumberIntVal(int64(math.Floor(val))), nil + + return cty.NumberVal(f.SetInt(i)), nil }, }) diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/sequence.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/sequence.go index d3cc341..6a6f66b 100644 --- a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/sequence.go +++ b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/sequence.go @@ -11,8 +11,9 @@ import ( var ConcatFunc = function.New(&function.Spec{ Params: []function.Parameter{}, VarParam: &function.Parameter{ - Name: "seqs", - Type: cty.DynamicPseudoType, + Name: "seqs", + Type: cty.DynamicPseudoType, + AllowMarked: true, }, Type: func(args []cty.Value) (ret cty.Type, err error) { if len(args) == 0 { @@ -42,6 +43,10 @@ var ConcatFunc = function.New(&function.Spec{ etys := make([]cty.Type, 0, len(args)) for i, val := range args { + // Discard marks for nested values, as we only need to handle types + // and lengths. + val, _ := val.UnmarkDeep() + ety := val.Type() switch { case ety.IsTupleType(): @@ -75,6 +80,7 @@ var ConcatFunc = function.New(&function.Spec{ // given values will be lists and that they will either be of // retType or of something we can convert to retType. vals := make([]cty.Value, 0, len(args)) + var markses []cty.ValueMarks // remember any marked lists we find for i, list := range args { list, err = convert.Convert(list, retType) if err != nil { @@ -83,6 +89,11 @@ var ConcatFunc = function.New(&function.Spec{ return cty.NilVal, function.NewArgError(i, err) } + list, listMarks := list.Unmark() + if len(listMarks) > 0 { + markses = append(markses, listMarks) + } + it := list.ElementIterator() for it.Next() { _, v := it.Element() @@ -90,10 +101,10 @@ var ConcatFunc = function.New(&function.Spec{ } } if len(vals) == 0 { - return cty.ListValEmpty(retType.ElementType()), nil + return cty.ListValEmpty(retType.ElementType()).WithMarks(markses...), nil } - return cty.ListVal(vals), nil + return cty.ListVal(vals).WithMarks(markses...), nil case retType.IsTupleType(): // If retType is a tuple type then we could have a mixture of // lists and tuples but we know they all have known values @@ -101,8 +112,14 @@ var ConcatFunc = function.New(&function.Spec{ // concatenating them all together will produce a tuple of // retType because of the work we did in the Type function above. vals := make([]cty.Value, 0, len(args)) + var markses []cty.ValueMarks // remember any marked seqs we find for _, seq := range args { + seq, seqMarks := seq.Unmark() + if len(seqMarks) > 0 { + markses = append(markses, seqMarks) + } + // Both lists and tuples support ElementIterator, so this is easy. it := seq.ElementIterator() for it.Next() { @@ -111,7 +128,7 @@ var ConcatFunc = function.New(&function.Spec{ } } - return cty.TupleVal(vals), nil + return cty.TupleVal(vals).WithMarks(markses...), nil default: // should never happen if Type is working correctly above panic("unsupported return type") diff --git a/vendor/github.com/zclconf/go-cty/cty/marks.go b/vendor/github.com/zclconf/go-cty/cty/marks.go index 4e1d3b1..b889e73 100644 --- a/vendor/github.com/zclconf/go-cty/cty/marks.go +++ b/vendor/github.com/zclconf/go-cty/cty/marks.go @@ -27,14 +27,32 @@ type marker struct { type ValueMarks map[interface{}]struct{} // NewValueMarks constructs a new ValueMarks set with the given mark values. +// +// If any of the arguments are already ValueMarks values then they'll be merged +// into the result, rather than used directly as individual marks. func NewValueMarks(marks ...interface{}) ValueMarks { if len(marks) == 0 { return nil } ret := make(ValueMarks, len(marks)) for _, v := range marks { + if vm, ok := v.(ValueMarks); ok { + // Constructing a new ValueMarks with an existing ValueMarks + // implements a merge operation. (This can cause our result to + // have a larger size than we expected, but that's okay.) + for v := range vm { + ret[v] = struct{}{} + } + continue + } ret[v] = struct{}{} } + if len(ret) == 0 { + // If we were merging ValueMarks values together and they were all + // empty then we'll avoid returning a zero-length map and return a + // nil instead, as is conventional. + return nil + } return ret } @@ -180,6 +198,9 @@ func (val Value) Mark(mark interface{}) Value { for k, v := range mr.marks { newMarker.marks[k] = v } + // unwrap the inner marked value, so we don't get multiple layers + // of marking. + newMarker.realV = mr.realV } else { // It's not a marker yet, so we're creating the first mark. newMarker.marks = make(ValueMarks, 1) diff --git a/vendor/github.com/zclconf/go-cty/cty/primitive_type.go b/vendor/github.com/zclconf/go-cty/cty/primitive_type.go index 7b3d119..6039017 100644 --- a/vendor/github.com/zclconf/go-cty/cty/primitive_type.go +++ b/vendor/github.com/zclconf/go-cty/cty/primitive_type.go @@ -52,6 +52,51 @@ func (t primitiveType) GoString() string { } } +// rawNumberEqual is our cty-specific definition of whether two big floats +// underlying cty.Number are "equal" for the purposes of the Value.Equals and +// Value.RawEquals methods. +// +// The built-in equality for big.Float is a direct comparison of the mantissa +// bits and the exponent, but that's too precise a check for cty because we +// routinely send numbers through decimal approximations and back and so +// we only promise to accurately represent the subset of binary floating point +// numbers that can be derived from a decimal string representation. +// +// In respect of the fact that cty only tries to preserve numbers that can +// reasonably be written in JSON documents, we use the string representation of +// a decimal approximation of the number as our comparison, relying on the +// big.Float type's heuristic for discarding extraneous mantissa bits that seem +// likely to only be there as a result of an earlier decimal-to-binary +// approximation during parsing, e.g. in ParseNumberVal. +func rawNumberEqual(a, b *big.Float) bool { + switch { + case (a == nil) != (b == nil): + return false + case a == nil: // b == nil too then, due to previous case + return true + default: + // This format and precision matches that used by cty/json.Marshal, + // and thus achieves our definition of "two numbers are equal if + // we'd use the same JSON serialization for both of them". + const format = 'f' + const prec = -1 + aStr := a.Text(format, prec) + bStr := b.Text(format, prec) + + // The one exception to our rule about equality-by-stringification is + // negative zero, because we want -0 to always be equal to +0. + const posZero = "0" + const negZero = "-0" + if aStr == negZero { + aStr = posZero + } + if bStr == negZero { + bStr = posZero + } + return aStr == bStr + } +} + // Number is the numeric type. Number values are arbitrary-precision // decimal numbers, which can then be converted into Go's various numeric // types only if they are in the appropriate range. diff --git a/vendor/github.com/zclconf/go-cty/cty/value_ops.go b/vendor/github.com/zclconf/go-cty/cty/value_ops.go index b33cc4f..cdcc150 100644 --- a/vendor/github.com/zclconf/go-cty/cty/value_ops.go +++ b/vendor/github.com/zclconf/go-cty/cty/value_ops.go @@ -116,9 +116,9 @@ func (val Value) GoString() string { // Use RawEquals to compare if two values are equal *ignoring* the // short-circuit rules and the exception for null values. func (val Value) Equals(other Value) Value { - if val.IsMarked() || other.IsMarked() { - val, valMarks := val.Unmark() - other, otherMarks := other.Unmark() + if val.ContainsMarked() || other.ContainsMarked() { + val, valMarks := val.UnmarkDeep() + other, otherMarks := other.UnmarkDeep() return val.Equals(other).WithMarks(valMarks, otherMarks) } @@ -191,7 +191,7 @@ func (val Value) Equals(other Value) Value { switch { case ty == Number: - result = val.v.(*big.Float).Cmp(other.v.(*big.Float)) == 0 + result = rawNumberEqual(val.v.(*big.Float), other.v.(*big.Float)) case ty == Bool: result = val.v.(bool) == other.v.(bool) case ty == String: @@ -492,18 +492,23 @@ func (val Value) RawEquals(other Value) bool { case ty.IsMapType(): ety := ty.typeImpl.(typeMap).ElementTypeT - if len(val.v.(map[string]interface{})) == len(other.v.(map[string]interface{})) { - for k := range val.v.(map[string]interface{}) { - if _, ok := other.v.(map[string]interface{})[k]; !ok { + if !val.HasSameMarks(other) { + return false + } + valUn, _ := val.Unmark() + otherUn, _ := other.Unmark() + if len(valUn.v.(map[string]interface{})) == len(otherUn.v.(map[string]interface{})) { + for k := range valUn.v.(map[string]interface{}) { + if _, ok := otherUn.v.(map[string]interface{})[k]; !ok { return false } lhs := Value{ ty: ety, - v: val.v.(map[string]interface{})[k], + v: valUn.v.(map[string]interface{})[k], } rhs := Value{ ty: ety, - v: other.v.(map[string]interface{})[k], + v: otherUn.v.(map[string]interface{})[k], } eq := lhs.RawEquals(rhs) if !eq { @@ -1278,9 +1283,7 @@ func (val Value) AsBigFloat() *big.Float { } // Copy the float so that callers can't mutate our internal state - ret := *(val.v.(*big.Float)) - - return &ret + return new(big.Float).Copy(val.v.(*big.Float)) } // AsValueSlice returns a []cty.Value representation of a non-null, non-unknown diff --git a/vendor/github.com/zclconf/go-cty/cty/walk.go b/vendor/github.com/zclconf/go-cty/cty/walk.go index d17f48c..87ba32e 100644 --- a/vendor/github.com/zclconf/go-cty/cty/walk.go +++ b/vendor/github.com/zclconf/go-cty/cty/walk.go @@ -33,10 +33,15 @@ func walk(path Path, val Value, cb func(Path, Value) (bool, error)) error { return nil } + // The callback already got a chance to see the mark in our + // call above, so can safely strip it off here in order to + // visit the child elements, which might still have their own marks. + rawVal, _ := val.Unmark() + ty := val.Type() switch { case ty.IsObjectType(): - for it := val.ElementIterator(); it.Next(); { + for it := rawVal.ElementIterator(); it.Next(); { nameVal, av := it.Element() path := append(path, GetAttrStep{ Name: nameVal.AsString(), @@ -46,8 +51,8 @@ func walk(path Path, val Value, cb func(Path, Value) (bool, error)) error { return err } } - case val.CanIterateElements(): - for it := val.ElementIterator(); it.Next(); { + case rawVal.CanIterateElements(): + for it := rawVal.ElementIterator(); it.Next(); { kv, ev := it.Element() path := append(path, IndexStep{ Key: kv, @@ -134,6 +139,12 @@ func transform(path Path, val Value, t Transformer) (Value, error) { ty := val.Type() var newVal Value + // We need to peel off any marks here so that we can dig around + // inside any collection values. We'll reapply these to any + // new collections we construct, but the transformer's Exit + // method gets the final say on what to do with those. + rawVal, marks := val.Unmark() + switch { case val.IsNull() || !val.IsKnown(): @@ -141,14 +152,14 @@ func transform(path Path, val Value, t Transformer) (Value, error) { newVal = val case ty.IsListType() || ty.IsSetType() || ty.IsTupleType(): - l := val.LengthInt() + l := rawVal.LengthInt() switch l { case 0: // No deep transform for an empty sequence newVal = val default: elems := make([]Value, 0, l) - for it := val.ElementIterator(); it.Next(); { + for it := rawVal.ElementIterator(); it.Next(); { kv, ev := it.Element() path := append(path, IndexStep{ Key: kv, @@ -161,25 +172,25 @@ func transform(path Path, val Value, t Transformer) (Value, error) { } switch { case ty.IsListType(): - newVal = ListVal(elems) + newVal = ListVal(elems).WithMarks(marks) case ty.IsSetType(): - newVal = SetVal(elems) + newVal = SetVal(elems).WithMarks(marks) case ty.IsTupleType(): - newVal = TupleVal(elems) + newVal = TupleVal(elems).WithMarks(marks) default: panic("unknown sequence type") // should never happen because of the case we are in } } case ty.IsMapType(): - l := val.LengthInt() + l := rawVal.LengthInt() switch l { case 0: // No deep transform for an empty map newVal = val default: elems := make(map[string]Value) - for it := val.ElementIterator(); it.Next(); { + for it := rawVal.ElementIterator(); it.Next(); { kv, ev := it.Element() path := append(path, IndexStep{ Key: kv, @@ -190,7 +201,7 @@ func transform(path Path, val Value, t Transformer) (Value, error) { } elems[kv.AsString()] = newEv } - newVal = MapVal(elems) + newVal = MapVal(elems).WithMarks(marks) } case ty.IsObjectType(): @@ -212,7 +223,7 @@ func transform(path Path, val Value, t Transformer) (Value, error) { } newAVs[name] = newAV } - newVal = ObjectVal(newAVs) + newVal = ObjectVal(newAVs).WithMarks(marks) } default: diff --git a/vendor/modules.txt b/vendor/modules.txt index 299f7f9..fa06850 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -36,7 +36,7 @@ github.com/pmezard/go-difflib/difflib ## explicit github.com/stretchr/testify/assert github.com/stretchr/testify/require -# github.com/zclconf/go-cty v1.8.1 +# github.com/zclconf/go-cty v1.10.0 ## explicit github.com/zclconf/go-cty/cty github.com/zclconf/go-cty/cty/convert