1package stdlib
2
3import (
4	"errors"
5	"fmt"
6	"sort"
7
8	"github.com/zclconf/go-cty/cty"
9	"github.com/zclconf/go-cty/cty/convert"
10	"github.com/zclconf/go-cty/cty/function"
11	"github.com/zclconf/go-cty/cty/gocty"
12)
13
14var HasIndexFunc = function.New(&function.Spec{
15	Params: []function.Parameter{
16		{
17			Name:             "collection",
18			Type:             cty.DynamicPseudoType,
19			AllowDynamicType: true,
20		},
21		{
22			Name:             "key",
23			Type:             cty.DynamicPseudoType,
24			AllowDynamicType: true,
25		},
26	},
27	Type: func(args []cty.Value) (ret cty.Type, err error) {
28		collTy := args[0].Type()
29		if !(collTy.IsTupleType() || collTy.IsListType() || collTy.IsMapType() || collTy == cty.DynamicPseudoType) {
30			return cty.NilType, fmt.Errorf("collection must be a list, a map or a tuple")
31		}
32		return cty.Bool, nil
33	},
34	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
35		return args[0].HasIndex(args[1]), nil
36	},
37})
38
39var IndexFunc = function.New(&function.Spec{
40	Params: []function.Parameter{
41		{
42			Name: "collection",
43			Type: cty.DynamicPseudoType,
44		},
45		{
46			Name:             "key",
47			Type:             cty.DynamicPseudoType,
48			AllowDynamicType: true,
49		},
50	},
51	Type: func(args []cty.Value) (ret cty.Type, err error) {
52		collTy := args[0].Type()
53		key := args[1]
54		keyTy := key.Type()
55		switch {
56		case collTy.IsTupleType():
57			if keyTy != cty.Number && keyTy != cty.DynamicPseudoType {
58				return cty.NilType, fmt.Errorf("key for tuple must be number")
59			}
60			if !key.IsKnown() {
61				return cty.DynamicPseudoType, nil
62			}
63			var idx int
64			err := gocty.FromCtyValue(key, &idx)
65			if err != nil {
66				return cty.NilType, fmt.Errorf("invalid key for tuple: %s", err)
67			}
68
69			etys := collTy.TupleElementTypes()
70
71			if idx >= len(etys) || idx < 0 {
72				return cty.NilType, fmt.Errorf("key must be between 0 and %d inclusive", len(etys))
73			}
74
75			return etys[idx], nil
76
77		case collTy.IsListType():
78			if keyTy != cty.Number && keyTy != cty.DynamicPseudoType {
79				return cty.NilType, fmt.Errorf("key for list must be number")
80			}
81
82			return collTy.ElementType(), nil
83
84		case collTy.IsMapType():
85			if keyTy != cty.String && keyTy != cty.DynamicPseudoType {
86				return cty.NilType, fmt.Errorf("key for map must be string")
87			}
88
89			return collTy.ElementType(), nil
90
91		default:
92			return cty.NilType, fmt.Errorf("collection must be a list, a map or a tuple")
93		}
94	},
95	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
96		has, err := HasIndex(args[0], args[1])
97		if err != nil {
98			return cty.NilVal, err
99		}
100		if has.False() { // safe because collection and key are guaranteed known here
101			return cty.NilVal, fmt.Errorf("invalid index")
102		}
103
104		return args[0].Index(args[1]), nil
105	},
106})
107
108var LengthFunc = function.New(&function.Spec{
109	Params: []function.Parameter{
110		{
111			Name:             "collection",
112			Type:             cty.DynamicPseudoType,
113			AllowDynamicType: true,
114			AllowMarked:      true,
115		},
116	},
117	Type: func(args []cty.Value) (ret cty.Type, err error) {
118		collTy := args[0].Type()
119		if !(collTy.IsTupleType() || collTy.IsListType() || collTy.IsMapType() || collTy.IsSetType() || collTy == cty.DynamicPseudoType) {
120			return cty.NilType, fmt.Errorf("collection must be a list, a map or a tuple")
121		}
122		return cty.Number, nil
123	},
124	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
125		return args[0].Length(), nil
126	},
127})
128
129var ElementFunc = function.New(&function.Spec{
130	Params: []function.Parameter{
131		{
132			Name:        "list",
133			Type:        cty.DynamicPseudoType,
134			AllowMarked: true,
135		},
136		{
137			Name: "index",
138			Type: cty.Number,
139		},
140	},
141	Type: func(args []cty.Value) (cty.Type, error) {
142		list := args[0]
143		index := args[1]
144		if index.IsKnown() {
145			if index.LessThan(cty.NumberIntVal(0)).True() {
146				return cty.DynamicPseudoType, fmt.Errorf("cannot use element function with a negative index")
147			}
148		}
149
150		listTy := list.Type()
151		switch {
152		case listTy.IsListType():
153			return listTy.ElementType(), nil
154		case listTy.IsTupleType():
155			if !args[1].IsKnown() {
156				// If the index isn't known yet then we can't predict the
157				// result type since each tuple element can have its own type.
158				return cty.DynamicPseudoType, nil
159			}
160
161			etys := listTy.TupleElementTypes()
162			var index int
163			err := gocty.FromCtyValue(args[1], &index)
164			if err != nil {
165				// e.g. fractional number where whole number is required
166				return cty.DynamicPseudoType, fmt.Errorf("invalid index: %s", err)
167			}
168			if len(etys) == 0 {
169				return cty.DynamicPseudoType, errors.New("cannot use element function with an empty list")
170			}
171			index = index % len(etys)
172			return etys[index], nil
173		default:
174			return cty.DynamicPseudoType, fmt.Errorf("cannot read elements from %s", listTy.FriendlyName())
175		}
176	},
177	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
178		var index int
179		err := gocty.FromCtyValue(args[1], &index)
180		if err != nil {
181			// can't happen because we checked this in the Type function above
182			return cty.DynamicVal, fmt.Errorf("invalid index: %s", err)
183		}
184
185		if args[1].LessThan(cty.NumberIntVal(0)).True() {
186			return cty.DynamicVal, fmt.Errorf("cannot use element function with a negative index")
187		}
188
189		input, marks := args[0].Unmark()
190		if !input.IsKnown() {
191			return cty.UnknownVal(retType), nil
192		}
193
194		l := input.LengthInt()
195		if l == 0 {
196			return cty.DynamicVal, errors.New("cannot use element function with an empty list")
197		}
198		index = index % l
199
200		// We did all the necessary type checks in the type function above,
201		// so this is guaranteed not to fail.
202		return input.Index(cty.NumberIntVal(int64(index))).WithMarks(marks), nil
203	},
204})
205
206// CoalesceListFunc is a function that takes any number of list arguments
207// and returns the first one that isn't empty.
208var CoalesceListFunc = function.New(&function.Spec{
209	Params: []function.Parameter{},
210	VarParam: &function.Parameter{
211		Name:             "vals",
212		Type:             cty.DynamicPseudoType,
213		AllowUnknown:     true,
214		AllowDynamicType: true,
215		AllowNull:        true,
216	},
217	Type: func(args []cty.Value) (ret cty.Type, err error) {
218		if len(args) == 0 {
219			return cty.NilType, errors.New("at least one argument is required")
220		}
221
222		argTypes := make([]cty.Type, len(args))
223
224		for i, arg := range args {
225			// if any argument is unknown, we can't be certain know which type we will return
226			if !arg.IsKnown() {
227				return cty.DynamicPseudoType, nil
228			}
229			ty := arg.Type()
230
231			if !ty.IsListType() && !ty.IsTupleType() {
232				return cty.NilType, errors.New("coalescelist arguments must be lists or tuples")
233			}
234
235			argTypes[i] = arg.Type()
236		}
237
238		last := argTypes[0]
239		// If there are mixed types, we have to return a dynamic type.
240		for _, next := range argTypes[1:] {
241			if !next.Equals(last) {
242				return cty.DynamicPseudoType, nil
243			}
244		}
245
246		return last, nil
247	},
248	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
249		for _, arg := range args {
250			if !arg.IsKnown() {
251				// If we run into an unknown list at some point, we can't
252				// predict the final result yet. (If there's a known, non-empty
253				// arg before this then we won't get here.)
254				return cty.UnknownVal(retType), nil
255			}
256
257			if arg.IsNull() {
258				continue
259			}
260
261			if arg.LengthInt() > 0 {
262				return arg, nil
263			}
264		}
265
266		return cty.NilVal, errors.New("no non-null arguments")
267	},
268})
269
270// CompactFunc is a function that takes a list of strings and returns a new list
271// with any empty string elements removed.
272var CompactFunc = function.New(&function.Spec{
273	Params: []function.Parameter{
274		{
275			Name: "list",
276			Type: cty.List(cty.String),
277		},
278	},
279	Type: function.StaticReturnType(cty.List(cty.String)),
280	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
281		listVal := args[0]
282		if !listVal.IsWhollyKnown() {
283			// If some of the element values aren't known yet then we
284			// can't yet return a compacted list
285			return cty.UnknownVal(retType), nil
286		}
287
288		var outputList []cty.Value
289
290		for it := listVal.ElementIterator(); it.Next(); {
291			_, v := it.Element()
292			if v.IsNull() || v.AsString() == "" {
293				continue
294			}
295			outputList = append(outputList, v)
296		}
297
298		if len(outputList) == 0 {
299			return cty.ListValEmpty(cty.String), nil
300		}
301
302		return cty.ListVal(outputList), nil
303	},
304})
305
306// ContainsFunc is a function that determines whether a given list or
307// set contains a given single value as one of its elements.
308var ContainsFunc = function.New(&function.Spec{
309	Params: []function.Parameter{
310		{
311			Name: "list",
312			Type: cty.DynamicPseudoType,
313		},
314		{
315			Name: "value",
316			Type: cty.DynamicPseudoType,
317		},
318	},
319	Type: function.StaticReturnType(cty.Bool),
320	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
321		arg := args[0]
322		ty := arg.Type()
323
324		if !ty.IsListType() && !ty.IsTupleType() && !ty.IsSetType() {
325			return cty.NilVal, errors.New("argument must be list, tuple, or set")
326		}
327
328		if args[0].IsNull() {
329			return cty.NilVal, errors.New("cannot search a nil list or set")
330		}
331
332		if args[0].LengthInt() == 0 {
333			return cty.False, nil
334		}
335
336		if !args[0].IsKnown() || !args[1].IsKnown() {
337			return cty.UnknownVal(cty.Bool), nil
338		}
339
340		containsUnknown := false
341		for it := args[0].ElementIterator(); it.Next(); {
342			_, v := it.Element()
343			eq := args[1].Equals(v)
344			if !eq.IsKnown() {
345				// We may have an unknown value which could match later, but we
346				// first need to continue checking all values for an exact
347				// match.
348				containsUnknown = true
349				continue
350			}
351			if eq.True() {
352				return cty.True, nil
353			}
354		}
355
356		if containsUnknown {
357			return cty.UnknownVal(cty.Bool), nil
358		}
359
360		return cty.False, nil
361	},
362})
363
364// DistinctFunc is a function that takes a list and returns a new list
365// with any duplicate elements removed.
366var DistinctFunc = function.New(&function.Spec{
367	Params: []function.Parameter{
368		{
369			Name: "list",
370			Type: cty.List(cty.DynamicPseudoType),
371		},
372	},
373	Type: func(args []cty.Value) (cty.Type, error) {
374		return args[0].Type(), nil
375	},
376	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
377		listVal := args[0]
378
379		if !listVal.IsWhollyKnown() {
380			return cty.UnknownVal(retType), nil
381		}
382		var list []cty.Value
383
384		for it := listVal.ElementIterator(); it.Next(); {
385			_, v := it.Element()
386			list, err = appendIfMissing(list, v)
387			if err != nil {
388				return cty.NilVal, err
389			}
390		}
391
392		if len(list) == 0 {
393			return cty.ListValEmpty(retType.ElementType()), nil
394		}
395		return cty.ListVal(list), nil
396	},
397})
398
399// ChunklistFunc is a function that splits a single list into fixed-size chunks,
400// returning a list of lists.
401var ChunklistFunc = function.New(&function.Spec{
402	Params: []function.Parameter{
403		{
404			Name:        "list",
405			Type:        cty.List(cty.DynamicPseudoType),
406			AllowMarked: true,
407		},
408		{
409			Name:        "size",
410			Type:        cty.Number,
411			AllowMarked: true,
412		},
413	},
414	Type: func(args []cty.Value) (cty.Type, error) {
415		return cty.List(args[0].Type()), nil
416	},
417	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
418		listVal := args[0]
419		sizeVal := args[1]
420		listVal, listMarks := listVal.Unmark()
421		sizeVal, sizeMarks := sizeVal.Unmark()
422		// All return paths below must include .WithMarks(retMarks) to propagate
423		// the top-level marks into the return value. Deep marks inside the
424		// list will just propagate naturally because we treat those values
425		// as opaque here.
426		retMarks := cty.NewValueMarks(listMarks, sizeMarks)
427
428		var size int
429		err = gocty.FromCtyValue(sizeVal, &size)
430		if err != nil {
431			return cty.NilVal, fmt.Errorf("invalid size: %s", err)
432		}
433
434		if size < 0 {
435			return cty.NilVal, errors.New("the size argument must be positive")
436		}
437
438		if listVal.LengthInt() == 0 {
439			return cty.ListValEmpty(listVal.Type()).WithMarks(retMarks), nil
440		}
441
442		output := make([]cty.Value, 0)
443
444		// if size is 0, returns a list made of the initial list
445		if size == 0 {
446			output = append(output, listVal)
447			return cty.ListVal(output).WithMarks(retMarks), nil
448		}
449
450		chunk := make([]cty.Value, 0)
451
452		l := listVal.LengthInt()
453		i := 0
454
455		for it := listVal.ElementIterator(); it.Next(); {
456			_, v := it.Element()
457			chunk = append(chunk, v)
458
459			// Chunk when index isn't 0, or when reaching the values's length
460			if (i+1)%size == 0 || (i+1) == l {
461				output = append(output, cty.ListVal(chunk))
462				chunk = make([]cty.Value, 0)
463			}
464			i++
465		}
466
467		return cty.ListVal(output).WithMarks(retMarks), nil
468	},
469})
470
471// FlattenFunc is a function that takes a list and replaces any elements
472// that are lists with a flattened sequence of the list contents.
473var FlattenFunc = function.New(&function.Spec{
474	Params: []function.Parameter{
475		{
476			Name:        "list",
477			Type:        cty.DynamicPseudoType,
478			AllowMarked: true,
479		},
480	},
481	Type: func(args []cty.Value) (cty.Type, error) {
482		if !args[0].IsWhollyKnown() {
483			return cty.DynamicPseudoType, nil
484		}
485
486		argTy := args[0].Type()
487		if !argTy.IsListType() && !argTy.IsSetType() && !argTy.IsTupleType() {
488			return cty.NilType, errors.New("can only flatten lists, sets and tuples")
489		}
490
491		// marks are attached to values, so ignore while determining type
492		retVal, _, known := flattener(args[0])
493		if !known {
494			return cty.DynamicPseudoType, nil
495		}
496
497		tys := make([]cty.Type, len(retVal))
498		for i, ty := range retVal {
499			tys[i] = ty.Type()
500		}
501		return cty.Tuple(tys), nil
502	},
503	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
504		inputList := args[0]
505
506		if unmarked, marks := inputList.Unmark(); unmarked.LengthInt() == 0 {
507			return cty.EmptyTupleVal.WithMarks(marks), nil
508		}
509
510		out, markses, known := flattener(inputList)
511		if !known {
512			return cty.UnknownVal(retType).WithMarks(markses...), nil
513		}
514
515		return cty.TupleVal(out).WithMarks(markses...), nil
516	},
517})
518
519// Flatten until it's not a cty.List, and return whether the value is known.
520// We can flatten lists with unknown values, as long as they are not
521// lists themselves.
522func flattener(flattenList cty.Value) ([]cty.Value, []cty.ValueMarks, bool) {
523	var markses []cty.ValueMarks
524	flattenList, flattenListMarks := flattenList.Unmark()
525	if len(flattenListMarks) > 0 {
526		markses = append(markses, flattenListMarks)
527	}
528	if !flattenList.Length().IsKnown() {
529		// If we don't know the length of what we're flattening then we can't
530		// predict the length of our result yet either.
531		return nil, markses, false
532	}
533
534	out := make([]cty.Value, 0)
535	isKnown := true
536	for it := flattenList.ElementIterator(); it.Next(); {
537		_, val := it.Element()
538
539		// Any dynamic types could result in more collections that need to be
540		// flattened, so the type cannot be known.
541		if val == cty.DynamicVal {
542			isKnown = false
543		}
544
545		if val.Type().IsListType() || val.Type().IsSetType() || val.Type().IsTupleType() {
546			if !val.IsKnown() {
547				isKnown = false
548				_, unknownMarks := val.Unmark()
549				markses = append(markses, unknownMarks)
550				continue
551			}
552
553			res, resMarks, known := flattener(val)
554			markses = append(markses, resMarks...)
555			if known {
556				out = append(out, res...)
557			} else {
558				isKnown = false
559			}
560		} else {
561			out = append(out, val)
562		}
563	}
564	return out, markses, isKnown
565}
566
567// KeysFunc is a function that takes a map and returns a sorted list of the map keys.
568var KeysFunc = function.New(&function.Spec{
569	Params: []function.Parameter{
570		{
571			Name:         "inputMap",
572			Type:         cty.DynamicPseudoType,
573			AllowUnknown: true,
574			AllowMarked:  true,
575		},
576	},
577	Type: func(args []cty.Value) (cty.Type, error) {
578		ty := args[0].Type()
579		switch {
580		case ty.IsMapType():
581			return cty.List(cty.String), nil
582		case ty.IsObjectType():
583			atys := ty.AttributeTypes()
584			if len(atys) == 0 {
585				return cty.EmptyTuple, nil
586			}
587			// All of our result elements will be strings, and atys just
588			// decides how many there are.
589			etys := make([]cty.Type, len(atys))
590			for i := range etys {
591				etys[i] = cty.String
592			}
593			return cty.Tuple(etys), nil
594		default:
595			return cty.DynamicPseudoType, function.NewArgErrorf(0, "must have map or object type")
596		}
597	},
598	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
599		// We must unmark the value before we can use ElementIterator on it, and
600		// then re-apply the same marks (possibly none) when we return. Since we
601		// don't mark map keys, we can throw away any nested marks, which would
602		// only apply to values.
603		m, marks := args[0].Unmark()
604		var keys []cty.Value
605
606		switch {
607		case m.Type().IsObjectType():
608			// In this case we allow unknown values so we must work only with
609			// the attribute _types_, not with the value itself.
610			var names []string
611			for name := range m.Type().AttributeTypes() {
612				names = append(names, name)
613			}
614			sort.Strings(names) // same ordering guaranteed by cty's ElementIterator
615			if len(names) == 0 {
616				return cty.EmptyTupleVal.WithMarks(marks), nil
617			}
618			keys = make([]cty.Value, len(names))
619			for i, name := range names {
620				keys[i] = cty.StringVal(name)
621			}
622			return cty.TupleVal(keys).WithMarks(marks), nil
623		default:
624			if !m.IsKnown() {
625				return cty.UnknownVal(retType).WithMarks(marks), nil
626			}
627
628			// cty guarantees that ElementIterator will iterate in lexicographical
629			// order by key.
630			for it := m.ElementIterator(); it.Next(); {
631				k, _ := it.Element()
632				keys = append(keys, k)
633			}
634			if len(keys) == 0 {
635				return cty.ListValEmpty(cty.String).WithMarks(marks), nil
636			}
637			return cty.ListVal(keys).WithMarks(marks), nil
638		}
639	},
640})
641
642// LookupFunc is a function that performs dynamic lookups of map types.
643var LookupFunc = function.New(&function.Spec{
644	Params: []function.Parameter{
645		{
646			Name:        "inputMap",
647			Type:        cty.DynamicPseudoType,
648			AllowMarked: true,
649		},
650		{
651			Name:        "key",
652			Type:        cty.String,
653			AllowMarked: true,
654		},
655		{
656			Name:        "default",
657			Type:        cty.DynamicPseudoType,
658			AllowMarked: true,
659		},
660	},
661	Type: func(args []cty.Value) (ret cty.Type, err error) {
662		ty := args[0].Type()
663
664		switch {
665		case ty.IsObjectType():
666			if !args[1].IsKnown() {
667				return cty.DynamicPseudoType, nil
668			}
669
670			keyVal, _ := args[1].Unmark()
671			key := keyVal.AsString()
672			if ty.HasAttribute(key) {
673				return args[0].GetAttr(key).Type(), nil
674			} else if len(args) == 3 {
675				// if the key isn't found but a default is provided,
676				// return the default type
677				return args[2].Type(), nil
678			}
679			return cty.DynamicPseudoType, function.NewArgErrorf(0, "the given object has no attribute %q", key)
680		case ty.IsMapType():
681			if len(args) == 3 {
682				_, err = convert.Convert(args[2], ty.ElementType())
683				if err != nil {
684					return cty.NilType, function.NewArgErrorf(2, "the default value must have the same type as the map elements")
685				}
686			}
687			return ty.ElementType(), nil
688		default:
689			return cty.NilType, function.NewArgErrorf(0, "lookup() requires a map as the first argument")
690		}
691	},
692	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
693		// leave default value marked
694		defaultVal := args[2]
695
696		var markses []cty.ValueMarks
697
698		// unmark collection, retain marks to reapply later
699		mapVar, mapMarks := args[0].Unmark()
700		markses = append(markses, mapMarks)
701
702		// include marks on the key in the result
703		keyVal, keyMarks := args[1].Unmark()
704		if len(keyMarks) > 0 {
705			markses = append(markses, keyMarks)
706		}
707		lookupKey := keyVal.AsString()
708
709		if !mapVar.IsWhollyKnown() {
710			return cty.UnknownVal(retType).WithMarks(markses...), nil
711		}
712
713		if mapVar.Type().IsObjectType() {
714			if mapVar.Type().HasAttribute(lookupKey) {
715				return mapVar.GetAttr(lookupKey).WithMarks(markses...), nil
716			}
717		} else if mapVar.HasIndex(cty.StringVal(lookupKey)) == cty.True {
718			return mapVar.Index(cty.StringVal(lookupKey)).WithMarks(markses...), nil
719		}
720
721		defaultVal, err = convert.Convert(defaultVal, retType)
722		if err != nil {
723			return cty.NilVal, err
724		}
725		return defaultVal.WithMarks(markses...), nil
726	},
727})
728
729// MergeFunc constructs a function that takes an arbitrary number of maps or
730// objects, and returns a single value that contains a merged set of keys and
731// values from all of the inputs.
732//
733// If more than one given map or object defines the same key then the one that
734// is later in the argument sequence takes precedence.
735var MergeFunc = function.New(&function.Spec{
736	Params: []function.Parameter{},
737	VarParam: &function.Parameter{
738		Name:             "maps",
739		Type:             cty.DynamicPseudoType,
740		AllowDynamicType: true,
741		AllowNull:        true,
742		AllowMarked:      true,
743	},
744	Type: func(args []cty.Value) (cty.Type, error) {
745		// empty args is accepted, so assume an empty object since we have no
746		// key-value types.
747		if len(args) == 0 {
748			return cty.EmptyObject, nil
749		}
750
751		// collect the possible object attrs
752		attrs := map[string]cty.Type{}
753
754		first := cty.NilType
755		matching := true
756		attrsKnown := true
757		for i, arg := range args {
758			ty := arg.Type()
759			// any dynamic args mean we can't compute a type
760			if ty.Equals(cty.DynamicPseudoType) {
761				return cty.DynamicPseudoType, nil
762			}
763
764			// check for invalid arguments
765			if !ty.IsMapType() && !ty.IsObjectType() {
766				return cty.NilType, fmt.Errorf("arguments must be maps or objects, got %#v", ty.FriendlyName())
767			}
768			// marks are attached to values, so ignore while determining type
769			arg, _ = arg.Unmark()
770
771			switch {
772			case ty.IsObjectType() && !arg.IsNull():
773				for attr, aty := range ty.AttributeTypes() {
774					attrs[attr] = aty
775				}
776			case ty.IsMapType():
777				switch {
778				case arg.IsNull():
779					// pass, nothing to add
780				case arg.IsKnown():
781					ety := arg.Type().ElementType()
782					for it := arg.ElementIterator(); it.Next(); {
783						attr, _ := it.Element()
784						attrs[attr.AsString()] = ety
785					}
786				default:
787					// any unknown maps means we don't know all possible attrs
788					// for the return type
789					attrsKnown = false
790				}
791			}
792
793			// record the first argument type for comparison
794			if i == 0 {
795				first = arg.Type()
796				continue
797			}
798
799			if !ty.Equals(first) && matching {
800				matching = false
801			}
802		}
803
804		// the types all match, so use the first argument type
805		if matching {
806			return first, nil
807		}
808
809		// We had a mix of unknown maps and objects, so we can't predict the
810		// attributes
811		if !attrsKnown {
812			return cty.DynamicPseudoType, nil
813		}
814
815		return cty.Object(attrs), nil
816	},
817	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
818		outputMap := make(map[string]cty.Value)
819		var markses []cty.ValueMarks // remember any marked maps/objects we find
820
821		for _, arg := range args {
822			if arg.IsNull() {
823				continue
824			}
825			arg, argMarks := arg.Unmark()
826			if len(argMarks) > 0 {
827				markses = append(markses, argMarks)
828			}
829			for it := arg.ElementIterator(); it.Next(); {
830				k, v := it.Element()
831				outputMap[k.AsString()] = v
832			}
833		}
834
835		switch {
836		case retType.IsMapType():
837			if len(outputMap) == 0 {
838				return cty.MapValEmpty(retType.ElementType()).WithMarks(markses...), nil
839			}
840			return cty.MapVal(outputMap).WithMarks(markses...), nil
841		case retType.IsObjectType(), retType.Equals(cty.DynamicPseudoType):
842			return cty.ObjectVal(outputMap).WithMarks(markses...), nil
843		default:
844			panic(fmt.Sprintf("unexpected return type: %#v", retType))
845		}
846	},
847})
848
849// ReverseListFunc takes a sequence and produces a new sequence of the same length
850// with all of the same elements as the given sequence but in reverse order.
851var ReverseListFunc = function.New(&function.Spec{
852	Params: []function.Parameter{
853		{
854			Name:        "list",
855			Type:        cty.DynamicPseudoType,
856			AllowMarked: true,
857		},
858	},
859	Type: func(args []cty.Value) (cty.Type, error) {
860		argTy := args[0].Type()
861		switch {
862		case argTy.IsTupleType():
863			argTys := argTy.TupleElementTypes()
864			retTys := make([]cty.Type, len(argTys))
865			for i, ty := range argTys {
866				retTys[len(retTys)-i-1] = ty
867			}
868			return cty.Tuple(retTys), nil
869		case argTy.IsListType(), argTy.IsSetType(): // We accept sets here to mimic the usual behavior of auto-converting to list
870			return cty.List(argTy.ElementType()), nil
871		default:
872			return cty.NilType, function.NewArgErrorf(0, "can only reverse list or tuple values, not %s", argTy.FriendlyName())
873		}
874	},
875	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
876		in, marks := args[0].Unmark()
877		inVals := in.AsValueSlice()
878		outVals := make([]cty.Value, len(inVals))
879
880		for i, v := range inVals {
881			outVals[len(outVals)-i-1] = v
882		}
883		switch {
884		case retType.IsTupleType():
885			return cty.TupleVal(outVals).WithMarks(marks), nil
886		default:
887			if len(outVals) == 0 {
888				return cty.ListValEmpty(retType.ElementType()).WithMarks(marks), nil
889			}
890			return cty.ListVal(outVals).WithMarks(marks), nil
891		}
892	},
893})
894
895// SetProductFunc calculates the Cartesian product of two or more sets or
896// sequences. If the arguments are all lists then the result is a list of tuples,
897// preserving the ordering of all of the input lists. Otherwise the result is a
898// set of tuples.
899var SetProductFunc = function.New(&function.Spec{
900	Params: []function.Parameter{},
901	VarParam: &function.Parameter{
902		Name:        "sets",
903		Type:        cty.DynamicPseudoType,
904		AllowMarked: true,
905	},
906	Type: func(args []cty.Value) (retType cty.Type, err error) {
907		if len(args) < 2 {
908			return cty.NilType, errors.New("at least two arguments are required")
909		}
910
911		listCount := 0
912		elemTys := make([]cty.Type, len(args))
913		for i, arg := range args {
914			aty := arg.Type()
915			switch {
916			case aty.IsSetType():
917				elemTys[i] = aty.ElementType()
918			case aty.IsListType():
919				elemTys[i] = aty.ElementType()
920				listCount++
921			case aty.IsTupleType():
922				// We can accept a tuple type only if there's some common type
923				// that all of its elements can be converted to.
924				allEtys := aty.TupleElementTypes()
925				if len(allEtys) == 0 {
926					elemTys[i] = cty.DynamicPseudoType
927					listCount++
928					break
929				}
930				ety, _ := convert.UnifyUnsafe(allEtys)
931				if ety == cty.NilType {
932					return cty.NilType, function.NewArgErrorf(i, "all elements must be of the same type")
933				}
934				elemTys[i] = ety
935				listCount++
936			default:
937				return cty.NilType, function.NewArgErrorf(i, "a set or a list is required")
938			}
939		}
940
941		if listCount == len(args) {
942			return cty.List(cty.Tuple(elemTys)), nil
943		}
944		return cty.Set(cty.Tuple(elemTys)), nil
945	},
946	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
947		ety := retType.ElementType()
948		var retMarks cty.ValueMarks
949
950		total := 1
951		var hasUnknownLength bool
952		for _, arg := range args {
953			arg, marks := arg.Unmark()
954			retMarks = cty.NewValueMarks(retMarks, marks)
955
956			// Continue processing after we find an argument with unknown
957			// length to ensure that we cover all the marks
958			if !arg.Length().IsKnown() {
959				hasUnknownLength = true
960				continue
961			}
962
963			// Because of our type checking function, we are guaranteed that
964			// all of the arguments are known, non-null values of types that
965			// support LengthInt.
966			total *= arg.LengthInt()
967		}
968
969		if hasUnknownLength {
970			return cty.UnknownVal(retType).WithMarks(retMarks), nil
971		}
972
973		if total == 0 {
974			// If any of the arguments was an empty collection then our result
975			// is also an empty collection, which we'll short-circuit here.
976			if retType.IsListType() {
977				return cty.ListValEmpty(ety).WithMarks(retMarks), nil
978			}
979			return cty.SetValEmpty(ety).WithMarks(retMarks), nil
980		}
981
982		subEtys := ety.TupleElementTypes()
983		product := make([][]cty.Value, total)
984
985		b := make([]cty.Value, total*len(args))
986		n := make([]int, len(args))
987		s := 0
988		argVals := make([][]cty.Value, len(args))
989		for i, arg := range args {
990			// We've already stored the marks in retMarks
991			arg, _ := arg.Unmark()
992			argVals[i] = arg.AsValueSlice()
993		}
994
995		for i := range product {
996			e := s + len(args)
997			pi := b[s:e]
998			product[i] = pi
999			s = e
1000
1001			for j, n := range n {
1002				val := argVals[j][n]
1003				ty := subEtys[j]
1004				if !val.Type().Equals(ty) {
1005					var err error
1006					val, err = convert.Convert(val, ty)
1007					if err != nil {
1008						// Should never happen since we checked this in our
1009						// type-checking function.
1010						return cty.NilVal, fmt.Errorf("failed to convert argVals[%d][%d] to %s; this is a bug in cty", j, n, ty.FriendlyName())
1011					}
1012				}
1013				pi[j] = val
1014			}
1015
1016			for j := len(n) - 1; j >= 0; j-- {
1017				n[j]++
1018				if n[j] < len(argVals[j]) {
1019					break
1020				}
1021				n[j] = 0
1022			}
1023		}
1024
1025		productVals := make([]cty.Value, total)
1026		for i, vals := range product {
1027			productVals[i] = cty.TupleVal(vals)
1028		}
1029
1030		if retType.IsListType() {
1031			return cty.ListVal(productVals).WithMarks(retMarks), nil
1032		}
1033		return cty.SetVal(productVals).WithMarks(retMarks), nil
1034	},
1035})
1036
1037// SliceFunc is a function that extracts some consecutive elements
1038// from within a list.
1039var SliceFunc = function.New(&function.Spec{
1040	Params: []function.Parameter{
1041		{
1042			Name:        "list",
1043			Type:        cty.DynamicPseudoType,
1044			AllowMarked: true,
1045		},
1046		{
1047			Name: "start_index",
1048			Type: cty.Number,
1049		},
1050		{
1051			Name: "end_index",
1052			Type: cty.Number,
1053		},
1054	},
1055	Type: func(args []cty.Value) (cty.Type, error) {
1056		arg := args[0]
1057		argTy := arg.Type()
1058
1059		if argTy.IsSetType() {
1060			return cty.NilType, function.NewArgErrorf(0, "cannot slice a set, because its elements do not have indices; explicitly convert to a list if the ordering of the result is not important")
1061		}
1062		if !argTy.IsListType() && !argTy.IsTupleType() {
1063			return cty.NilType, function.NewArgErrorf(0, "must be a list or tuple value")
1064		}
1065
1066		startIndex, endIndex, idxsKnown, err := sliceIndexes(args)
1067		if err != nil {
1068			return cty.NilType, err
1069		}
1070
1071		if argTy.IsListType() {
1072			return argTy, nil
1073		}
1074
1075		if !idxsKnown {
1076			// If we don't know our start/end indices then we can't predict
1077			// the result type if we're planning to return a tuple.
1078			return cty.DynamicPseudoType, nil
1079		}
1080		return cty.Tuple(argTy.TupleElementTypes()[startIndex:endIndex]), nil
1081	},
1082	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
1083		inputList, marks := args[0].Unmark()
1084
1085		if retType == cty.DynamicPseudoType {
1086			return cty.DynamicVal.WithMarks(marks), nil
1087		}
1088
1089		// we ignore idxsKnown return value here because the indices are always
1090		// known here, or else the call would've short-circuited.
1091		startIndex, endIndex, _, err := sliceIndexes(args)
1092		if err != nil {
1093			return cty.NilVal, err
1094		}
1095
1096		if endIndex-startIndex == 0 {
1097			if retType.IsTupleType() {
1098				return cty.EmptyTupleVal.WithMarks(marks), nil
1099			}
1100			return cty.ListValEmpty(retType.ElementType()).WithMarks(marks), nil
1101		}
1102
1103		outputList := inputList.AsValueSlice()[startIndex:endIndex]
1104
1105		if retType.IsTupleType() {
1106			return cty.TupleVal(outputList).WithMarks(marks), nil
1107		}
1108
1109		return cty.ListVal(outputList).WithMarks(marks), nil
1110	},
1111})
1112
1113func sliceIndexes(args []cty.Value) (int, int, bool, error) {
1114	var startIndex, endIndex, length int
1115	var startKnown, endKnown, lengthKnown bool
1116
1117	// remove marks from args[0]
1118	list, _ := args[0].Unmark()
1119
1120	// If it's a tuple then we always know the length by the type, but collections might be unknown or have unknown length
1121	if list.Type().IsTupleType() || list.Length().IsKnown() {
1122		length = list.LengthInt()
1123		lengthKnown = true
1124	}
1125
1126	if args[1].IsKnown() {
1127		if err := gocty.FromCtyValue(args[1], &startIndex); err != nil {
1128			return 0, 0, false, function.NewArgErrorf(1, "invalid start index: %s", err)
1129		}
1130		if startIndex < 0 {
1131			return 0, 0, false, function.NewArgErrorf(1, "start index must not be less than zero")
1132		}
1133		if lengthKnown && startIndex > length {
1134			return 0, 0, false, function.NewArgErrorf(1, "start index must not be greater than the length of the list")
1135		}
1136		startKnown = true
1137	}
1138	if args[2].IsKnown() {
1139		if err := gocty.FromCtyValue(args[2], &endIndex); err != nil {
1140			return 0, 0, false, function.NewArgErrorf(2, "invalid end index: %s", err)
1141		}
1142		if endIndex < 0 {
1143			return 0, 0, false, function.NewArgErrorf(2, "end index must not be less than zero")
1144		}
1145		if lengthKnown && endIndex > length {
1146			return 0, 0, false, function.NewArgErrorf(2, "end index must not be greater than the length of the list")
1147		}
1148		endKnown = true
1149	}
1150	if startKnown && endKnown {
1151		if startIndex > endIndex {
1152			return 0, 0, false, function.NewArgErrorf(1, "start index must not be greater than end index")
1153		}
1154	}
1155	return startIndex, endIndex, startKnown && endKnown, nil
1156}
1157
1158// ValuesFunc is a function that returns a list of the map values,
1159// in the order of the sorted keys.
1160var ValuesFunc = function.New(&function.Spec{
1161	Params: []function.Parameter{
1162		{
1163			Name:        "values",
1164			Type:        cty.DynamicPseudoType,
1165			AllowMarked: true,
1166		},
1167	},
1168	Type: func(args []cty.Value) (ret cty.Type, err error) {
1169		ty := args[0].Type()
1170		if ty.IsMapType() {
1171			return cty.List(ty.ElementType()), nil
1172		} else if ty.IsObjectType() {
1173			// The result is a tuple type with all of the same types as our
1174			// object type's attributes, sorted in lexicographical order by the
1175			// keys. (This matches the sort order guaranteed by ElementIterator
1176			// on a cty object value.)
1177			atys := ty.AttributeTypes()
1178			if len(atys) == 0 {
1179				return cty.EmptyTuple, nil
1180			}
1181			attrNames := make([]string, 0, len(atys))
1182			for name := range atys {
1183				attrNames = append(attrNames, name)
1184			}
1185			sort.Strings(attrNames)
1186
1187			tys := make([]cty.Type, len(attrNames))
1188			for i, name := range attrNames {
1189				tys[i] = atys[name]
1190			}
1191			return cty.Tuple(tys), nil
1192		}
1193		return cty.NilType, errors.New("values() requires a map as the first argument")
1194	},
1195	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
1196		mapVar := args[0]
1197
1198		// We must unmark the value before we can use ElementIterator on it,
1199		// and then re-apply the same marks (possibly none) when we return.
1200		// (We leave the inner values just as they are, because we won't be
1201		// doing anything with them aside from copying them verbatim into the
1202		// result, marks and all.)
1203		mapVar, marks := mapVar.Unmark()
1204
1205		// We can just iterate the map/object value here because cty guarantees
1206		// that these types always iterate in key lexicographical order.
1207		var values []cty.Value
1208		for it := mapVar.ElementIterator(); it.Next(); {
1209			_, val := it.Element()
1210			values = append(values, val)
1211		}
1212
1213		// All of the return paths must include .WithMarks(marks) so that we
1214		// will preserve the markings of the overall map/object we were given.
1215		if retType.IsTupleType() {
1216			return cty.TupleVal(values).WithMarks(marks), nil
1217		}
1218		if len(values) == 0 {
1219			return cty.ListValEmpty(retType.ElementType()).WithMarks(marks), nil
1220		}
1221		return cty.ListVal(values).WithMarks(marks), nil
1222	},
1223})
1224
1225// ZipmapFunc is a function that constructs a map from a list of keys
1226// and a corresponding list of values.
1227var ZipmapFunc = function.New(&function.Spec{
1228	Params: []function.Parameter{
1229		{
1230			Name:        "keys",
1231			Type:        cty.List(cty.String),
1232			AllowMarked: true,
1233		},
1234		{
1235			Name:        "values",
1236			Type:        cty.DynamicPseudoType,
1237			AllowMarked: true,
1238		},
1239	},
1240	Type: func(args []cty.Value) (ret cty.Type, err error) {
1241		keys := args[0]
1242		values := args[1]
1243		valuesTy := values.Type()
1244
1245		switch {
1246		case valuesTy.IsListType():
1247			return cty.Map(values.Type().ElementType()), nil
1248		case valuesTy.IsTupleType():
1249			if !keys.IsWhollyKnown() {
1250				// Since zipmap with a tuple produces an object, we need to know
1251				// all of the key names before we can predict our result type.
1252				return cty.DynamicPseudoType, nil
1253			}
1254
1255			// NOTE: Marking of the keys list can't be represented in the
1256			// result type, so the tuple type here will disclose the keys.
1257			// This is unfortunate but is a common compromise with dynamic
1258			// return types; the result from Impl will still reflect the marks
1259			// from the keys list, so a mark-using caller should look out for
1260			// that if it's important for their use-case.
1261			keys, _ := keys.Unmark()
1262			keysRaw := keys.AsValueSlice()
1263			valueTypesRaw := valuesTy.TupleElementTypes()
1264			if len(keysRaw) != len(valueTypesRaw) {
1265				return cty.NilType, fmt.Errorf("number of keys (%d) does not match number of values (%d)", len(keysRaw), len(valueTypesRaw))
1266			}
1267			atys := make(map[string]cty.Type, len(valueTypesRaw))
1268			for i, keyVal := range keysRaw {
1269				keyVal, _ = keyVal.Unmark()
1270				if keyVal.IsNull() {
1271					return cty.NilType, fmt.Errorf("keys list has null value at index %d", i)
1272				}
1273				key := keyVal.AsString()
1274				atys[key] = valueTypesRaw[i]
1275			}
1276			return cty.Object(atys), nil
1277
1278		default:
1279			return cty.NilType, errors.New("values argument must be a list or tuple value")
1280		}
1281	},
1282	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
1283		keys := args[0]
1284		values := args[1]
1285		keys, keysMarks := keys.Unmark()
1286		values, valuesMarks := values.Unmark()
1287
1288		// All of our return paths must pass through the merged marks from
1289		// both the keys and the values, if any, using .WithMarks(retMarks)
1290		retMarks := cty.NewValueMarks(keysMarks, valuesMarks)
1291
1292		if !keys.IsWhollyKnown() {
1293			// Unknown map keys and object attributes are not supported, so
1294			// our entire result must be unknown in this case.
1295			return cty.UnknownVal(retType).WithMarks(retMarks), nil
1296		}
1297
1298		// both keys and values are guaranteed to be shallowly-known here,
1299		// because our declared params above don't allow unknown or null values.
1300		if keys.LengthInt() != values.LengthInt() {
1301			return cty.NilVal, fmt.Errorf("number of keys (%d) does not match number of values (%d)", keys.LengthInt(), values.LengthInt())
1302		}
1303
1304		output := make(map[string]cty.Value)
1305
1306		i := 0
1307		for it := keys.ElementIterator(); it.Next(); {
1308			_, v := it.Element()
1309			v, vMarks := v.Unmark()
1310			val := values.Index(cty.NumberIntVal(int64(i)))
1311			output[v.AsString()] = val
1312
1313			// We also need to accumulate the individual key marks on the
1314			// returned map, because keys can't carry marks on their own.
1315			retMarks = cty.NewValueMarks(retMarks, vMarks)
1316
1317			i++
1318		}
1319
1320		switch {
1321		case retType.IsMapType():
1322			if len(output) == 0 {
1323				return cty.MapValEmpty(retType.ElementType()).WithMarks(retMarks), nil
1324			}
1325			return cty.MapVal(output).WithMarks(retMarks), nil
1326		case retType.IsObjectType():
1327			return cty.ObjectVal(output).WithMarks(retMarks), nil
1328		default:
1329			// Should never happen because the type-check function should've
1330			// caught any other case.
1331			return cty.NilVal, fmt.Errorf("internally selected incorrect result type %s (this is a bug)", retType.FriendlyName())
1332		}
1333	},
1334})
1335
1336// helper function to add an element to a list, if it does not already exist
1337func appendIfMissing(slice []cty.Value, element cty.Value) ([]cty.Value, error) {
1338	for _, ele := range slice {
1339		eq, err := Equal(ele, element)
1340		if err != nil {
1341			return slice, err
1342		}
1343		if eq.True() {
1344			return slice, nil
1345		}
1346	}
1347	return append(slice, element), nil
1348}
1349
1350// HasIndex determines whether the given collection can be indexed with the
1351// given key.
1352func HasIndex(collection cty.Value, key cty.Value) (cty.Value, error) {
1353	return HasIndexFunc.Call([]cty.Value{collection, key})
1354}
1355
1356// Index returns an element from the given collection using the given key,
1357// or returns an error if there is no element for the given key.
1358func Index(collection cty.Value, key cty.Value) (cty.Value, error) {
1359	return IndexFunc.Call([]cty.Value{collection, key})
1360}
1361
1362// Length returns the number of elements in the given collection.
1363func Length(collection cty.Value) (cty.Value, error) {
1364	return LengthFunc.Call([]cty.Value{collection})
1365}
1366
1367// Element returns a single element from a given list at the given index. If
1368// index is greater than the length of the list then it is wrapped modulo
1369// the list length.
1370func Element(list, index cty.Value) (cty.Value, error) {
1371	return ElementFunc.Call([]cty.Value{list, index})
1372}
1373
1374// CoalesceList takes any number of list arguments and returns the first one that isn't empty.
1375func CoalesceList(args ...cty.Value) (cty.Value, error) {
1376	return CoalesceListFunc.Call(args)
1377}
1378
1379// Compact takes a list of strings and returns a new list
1380// with any empty string elements removed.
1381func Compact(list cty.Value) (cty.Value, error) {
1382	return CompactFunc.Call([]cty.Value{list})
1383}
1384
1385// Contains determines whether a given list contains a given single value
1386// as one of its elements.
1387func Contains(list, value cty.Value) (cty.Value, error) {
1388	return ContainsFunc.Call([]cty.Value{list, value})
1389}
1390
1391// Distinct takes a list and returns a new list with any duplicate elements removed.
1392func Distinct(list cty.Value) (cty.Value, error) {
1393	return DistinctFunc.Call([]cty.Value{list})
1394}
1395
1396// Chunklist splits a single list into fixed-size chunks, returning a list of lists.
1397func Chunklist(list, size cty.Value) (cty.Value, error) {
1398	return ChunklistFunc.Call([]cty.Value{list, size})
1399}
1400
1401// Flatten takes a list and replaces any elements that are lists with a flattened
1402// sequence of the list contents.
1403func Flatten(list cty.Value) (cty.Value, error) {
1404	return FlattenFunc.Call([]cty.Value{list})
1405}
1406
1407// Keys takes a map and returns a sorted list of the map keys.
1408func Keys(inputMap cty.Value) (cty.Value, error) {
1409	return KeysFunc.Call([]cty.Value{inputMap})
1410}
1411
1412// Lookup performs a dynamic lookup into a map.
1413// There are two required arguments, map and key, plus an optional default,
1414// which is a value to return if no key is found in map.
1415func Lookup(inputMap, key, defaultValue cty.Value) (cty.Value, error) {
1416	return LookupFunc.Call([]cty.Value{inputMap, key, defaultValue})
1417}
1418
1419// Merge takes an arbitrary number of maps and returns a single map that contains
1420// a merged set of elements from all of the maps.
1421//
1422// If more than one given map defines the same key then the one that is later in
1423// the argument sequence takes precedence.
1424func Merge(maps ...cty.Value) (cty.Value, error) {
1425	return MergeFunc.Call(maps)
1426}
1427
1428// ReverseList takes a sequence and produces a new sequence of the same length
1429// with all of the same elements as the given sequence but in reverse order.
1430func ReverseList(list cty.Value) (cty.Value, error) {
1431	return ReverseListFunc.Call([]cty.Value{list})
1432}
1433
1434// SetProduct computes the Cartesian product of sets or sequences.
1435func SetProduct(sets ...cty.Value) (cty.Value, error) {
1436	return SetProductFunc.Call(sets)
1437}
1438
1439// Slice extracts some consecutive elements from within a list.
1440func Slice(list, start, end cty.Value) (cty.Value, error) {
1441	return SliceFunc.Call([]cty.Value{list, start, end})
1442}
1443
1444// Values returns a list of the map values, in the order of the sorted keys.
1445// This function only works on flat maps.
1446func Values(values cty.Value) (cty.Value, error) {
1447	return ValuesFunc.Call([]cty.Value{values})
1448}
1449
1450// Zipmap constructs a map from a list of keys and a corresponding list of values.
1451func Zipmap(keys, values cty.Value) (cty.Value, error) {
1452	return ZipmapFunc.Call([]cty.Value{keys, values})
1453}
1454