github.com/hashicorp/terraform-plugin-sdk@v1.17.2/internal/lang/funcs/collection.go (about)

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