github.com/khulnasoft-lab/defsec@v1.0.5-0.20230827010352-5e9f46893d95/pkg/scanners/terraform/parser/funcs/collection.go (about)

     1  // Copied from github.com/hashicorp/terraform/internal/lang/funcs
     2  package funcs
     3  
     4  import (
     5  	"errors"
     6  	"fmt"
     7  	"math/big"
     8  	"sort"
     9  
    10  	"github.com/zclconf/go-cty/cty"
    11  	"github.com/zclconf/go-cty/cty/convert"
    12  	"github.com/zclconf/go-cty/cty/function"
    13  	"github.com/zclconf/go-cty/cty/function/stdlib"
    14  	"github.com/zclconf/go-cty/cty/gocty"
    15  )
    16  
    17  var LengthFunc = function.New(&function.Spec{
    18  	Params: []function.Parameter{
    19  		{
    20  			Name:             "value",
    21  			Type:             cty.DynamicPseudoType,
    22  			AllowDynamicType: true,
    23  			AllowUnknown:     true,
    24  			AllowMarked:      true,
    25  		},
    26  	},
    27  	Type: func(args []cty.Value) (cty.Type, error) {
    28  		collTy := args[0].Type()
    29  		switch {
    30  		case collTy == cty.String || collTy.IsTupleType() || collTy.IsObjectType() || collTy.IsListType() || collTy.IsMapType() || collTy.IsSetType() || collTy == cty.DynamicPseudoType:
    31  			return cty.Number, nil
    32  		default:
    33  			return cty.Number, errors.New("argument must be a string, a collection type, or a structural type")
    34  		}
    35  	},
    36  	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
    37  		coll := args[0]
    38  		collTy := args[0].Type()
    39  		marks := coll.Marks()
    40  		switch {
    41  		case collTy == cty.DynamicPseudoType:
    42  			return cty.UnknownVal(cty.Number).WithMarks(marks), nil
    43  		case collTy.IsTupleType():
    44  			l := len(collTy.TupleElementTypes())
    45  			return cty.NumberIntVal(int64(l)).WithMarks(marks), nil
    46  		case collTy.IsObjectType():
    47  			l := len(collTy.AttributeTypes())
    48  			return cty.NumberIntVal(int64(l)).WithMarks(marks), nil
    49  		case collTy == cty.String:
    50  			// We'll delegate to the cty stdlib strlen function here, because
    51  			// it deals with all of the complexities of tokenizing unicode
    52  			// grapheme clusters.
    53  			return stdlib.Strlen(coll)
    54  		case collTy.IsListType() || collTy.IsSetType() || collTy.IsMapType():
    55  			return coll.Length(), nil
    56  		default:
    57  			// Should never happen, because of the checks in our Type func above
    58  			return cty.UnknownVal(cty.Number), errors.New("impossible value type for length(...)")
    59  		}
    60  	},
    61  })
    62  
    63  // AllTrueFunc constructs a function that returns true if all elements of the
    64  // list are true. If the list is empty, return true.
    65  var AllTrueFunc = function.New(&function.Spec{
    66  	Params: []function.Parameter{
    67  		{
    68  			Name: "list",
    69  			Type: cty.List(cty.Bool),
    70  		},
    71  	},
    72  	Type: function.StaticReturnType(cty.Bool),
    73  	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
    74  		result := cty.True
    75  		for it := args[0].ElementIterator(); it.Next(); {
    76  			_, v := it.Element()
    77  			if !v.IsKnown() {
    78  				return cty.UnknownVal(cty.Bool), nil
    79  			}
    80  			if v.IsNull() {
    81  				return cty.False, nil
    82  			}
    83  			result = result.And(v)
    84  			if result.False() {
    85  				return cty.False, nil
    86  			}
    87  		}
    88  		return result, nil
    89  	},
    90  })
    91  
    92  // AnyTrueFunc constructs a function that returns true if any element of the
    93  // list is true. If the list is empty, return false.
    94  var AnyTrueFunc = function.New(&function.Spec{
    95  	Params: []function.Parameter{
    96  		{
    97  			Name: "list",
    98  			Type: cty.List(cty.Bool),
    99  		},
   100  	},
   101  	Type: function.StaticReturnType(cty.Bool),
   102  	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
   103  		result := cty.False
   104  		var hasUnknown bool
   105  		for it := args[0].ElementIterator(); it.Next(); {
   106  			_, v := it.Element()
   107  			if !v.IsKnown() {
   108  				hasUnknown = true
   109  				continue
   110  			}
   111  			if v.IsNull() {
   112  				continue
   113  			}
   114  			result = result.Or(v)
   115  			if result.True() {
   116  				return cty.True, nil
   117  			}
   118  		}
   119  		if hasUnknown {
   120  			return cty.UnknownVal(cty.Bool), nil
   121  		}
   122  		return result, nil
   123  	},
   124  })
   125  
   126  // CoalesceFunc constructs a function that takes any number of arguments and
   127  // returns the first one that isn't empty. This function was copied from go-cty
   128  // stdlib and modified so that it returns the first *non-empty* non-null element
   129  // from a sequence, instead of merely the first non-null.
   130  var CoalesceFunc = function.New(&function.Spec{
   131  	Params: []function.Parameter{},
   132  	VarParam: &function.Parameter{
   133  		Name:             "vals",
   134  		Type:             cty.DynamicPseudoType,
   135  		AllowUnknown:     true,
   136  		AllowDynamicType: true,
   137  		AllowNull:        true,
   138  	},
   139  	Type: func(args []cty.Value) (ret cty.Type, err error) {
   140  		argTypes := make([]cty.Type, len(args))
   141  		for i, val := range args {
   142  			argTypes[i] = val.Type()
   143  		}
   144  		retType, _ := convert.UnifyUnsafe(argTypes)
   145  		if retType == cty.NilType {
   146  			return cty.NilType, errors.New("all arguments must have the same type")
   147  		}
   148  		return retType, nil
   149  	},
   150  	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
   151  		for _, argVal := range args {
   152  			// We already know this will succeed because of the checks in our Type func above
   153  			argVal, _ = convert.Convert(argVal, retType)
   154  			if !argVal.IsKnown() {
   155  				return cty.UnknownVal(retType), nil
   156  			}
   157  			if argVal.IsNull() {
   158  				continue
   159  			}
   160  			if retType == cty.String && argVal.RawEquals(cty.StringVal("")) {
   161  				continue
   162  			}
   163  
   164  			return argVal, nil
   165  		}
   166  		return cty.NilVal, errors.New("no non-null, non-empty-string arguments")
   167  	},
   168  })
   169  
   170  // IndexFunc constructs a function that finds the element index for a given value in a list.
   171  var IndexFunc = function.New(&function.Spec{
   172  	Params: []function.Parameter{
   173  		{
   174  			Name: "list",
   175  			Type: cty.DynamicPseudoType,
   176  		},
   177  		{
   178  			Name: "value",
   179  			Type: cty.DynamicPseudoType,
   180  		},
   181  	},
   182  	Type: function.StaticReturnType(cty.Number),
   183  	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
   184  		if !(args[0].Type().IsListType() || args[0].Type().IsTupleType()) {
   185  			return cty.NilVal, errors.New("argument must be a list or tuple")
   186  		}
   187  
   188  		if !args[0].IsKnown() {
   189  			return cty.UnknownVal(cty.Number), nil
   190  		}
   191  
   192  		if args[0].LengthInt() == 0 { // Easy path
   193  			return cty.NilVal, errors.New("cannot search an empty list")
   194  		}
   195  
   196  		for it := args[0].ElementIterator(); it.Next(); {
   197  			i, v := it.Element()
   198  			eq, err := stdlib.Equal(v, args[1])
   199  			if err != nil {
   200  				return cty.NilVal, err
   201  			}
   202  			if !eq.IsKnown() {
   203  				return cty.UnknownVal(cty.Number), nil
   204  			}
   205  			if eq.True() {
   206  				return i, nil
   207  			}
   208  		}
   209  		return cty.NilVal, errors.New("item not found")
   210  
   211  	},
   212  })
   213  
   214  // LookupFunc constructs a function that performs dynamic lookups of map types.
   215  var LookupFunc = function.New(&function.Spec{
   216  	Params: []function.Parameter{
   217  		{
   218  			Name:        "inputMap",
   219  			Type:        cty.DynamicPseudoType,
   220  			AllowMarked: true,
   221  		},
   222  		{
   223  			Name:        "key",
   224  			Type:        cty.String,
   225  			AllowMarked: true,
   226  		},
   227  	},
   228  	VarParam: &function.Parameter{
   229  		Name:             "default",
   230  		Type:             cty.DynamicPseudoType,
   231  		AllowUnknown:     true,
   232  		AllowDynamicType: true,
   233  		AllowNull:        true,
   234  		AllowMarked:      true,
   235  	},
   236  	Type: func(args []cty.Value) (ret cty.Type, err error) {
   237  		if len(args) < 1 || len(args) > 3 {
   238  			return cty.NilType, fmt.Errorf("lookup() takes two or three arguments, got %d", len(args))
   239  		}
   240  
   241  		ty := args[0].Type()
   242  
   243  		switch {
   244  		case ty.IsObjectType():
   245  			if !args[1].IsKnown() {
   246  				return cty.DynamicPseudoType, nil
   247  			}
   248  
   249  			keyVal, _ := args[1].Unmark()
   250  			key := keyVal.AsString()
   251  			if ty.HasAttribute(key) {
   252  				return args[0].GetAttr(key).Type(), nil
   253  			} else if len(args) == 3 {
   254  				// if the key isn't found but a default is provided,
   255  				// return the default type
   256  				return args[2].Type(), nil
   257  			}
   258  			return cty.DynamicPseudoType, function.NewArgErrorf(0, "the given object has no attribute %q", key)
   259  		case ty.IsMapType():
   260  			if len(args) == 3 {
   261  				_, err = convert.Convert(args[2], ty.ElementType())
   262  				if err != nil {
   263  					return cty.NilType, function.NewArgErrorf(2, "the default value must have the same type as the map elements")
   264  				}
   265  			}
   266  			return ty.ElementType(), nil
   267  		default:
   268  			return cty.NilType, function.NewArgErrorf(0, "lookup() requires a map as the first argument")
   269  		}
   270  	},
   271  	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
   272  		var defaultVal cty.Value
   273  		defaultValueSet := false
   274  
   275  		if len(args) == 3 {
   276  			// intentionally leave default value marked
   277  			defaultVal = args[2]
   278  			defaultValueSet = true
   279  		}
   280  
   281  		// keep track of marks from the collection and key
   282  		var markses []cty.ValueMarks
   283  
   284  		// unmark collection, retain marks to reapply later
   285  		mapVar, mapMarks := args[0].Unmark()
   286  		markses = append(markses, mapMarks)
   287  
   288  		// include marks on the key in the result
   289  		keyVal, keyMarks := args[1].Unmark()
   290  		if len(keyMarks) > 0 {
   291  			markses = append(markses, keyMarks)
   292  		}
   293  		lookupKey := keyVal.AsString()
   294  
   295  		if !mapVar.IsKnown() {
   296  			return cty.UnknownVal(retType).WithMarks(markses...), nil
   297  		}
   298  
   299  		if mapVar.Type().IsObjectType() {
   300  			if mapVar.Type().HasAttribute(lookupKey) {
   301  				return mapVar.GetAttr(lookupKey).WithMarks(markses...), nil
   302  			}
   303  		} else if mapVar.HasIndex(cty.StringVal(lookupKey)) == cty.True {
   304  			return mapVar.Index(cty.StringVal(lookupKey)).WithMarks(markses...), nil
   305  		}
   306  
   307  		if defaultValueSet {
   308  			defaultVal, err = convert.Convert(defaultVal, retType)
   309  			if err != nil {
   310  				return cty.NilVal, err
   311  			}
   312  			return defaultVal.WithMarks(markses...), nil
   313  		}
   314  
   315  		return cty.UnknownVal(cty.DynamicPseudoType).WithMarks(markses...), fmt.Errorf(
   316  			"lookup failed to find '%s'", lookupKey)
   317  	},
   318  })
   319  
   320  // MatchkeysFunc constructs a function that constructs a new list by taking a
   321  // subset of elements from one list whose indexes match the corresponding
   322  // indexes of values in another list.
   323  var MatchkeysFunc = function.New(&function.Spec{
   324  	Params: []function.Parameter{
   325  		{
   326  			Name: "values",
   327  			Type: cty.List(cty.DynamicPseudoType),
   328  		},
   329  		{
   330  			Name: "keys",
   331  			Type: cty.List(cty.DynamicPseudoType),
   332  		},
   333  		{
   334  			Name: "searchset",
   335  			Type: cty.List(cty.DynamicPseudoType),
   336  		},
   337  	},
   338  	Type: func(args []cty.Value) (cty.Type, error) {
   339  		ty, _ := convert.UnifyUnsafe([]cty.Type{args[1].Type(), args[2].Type()})
   340  		if ty == cty.NilType {
   341  			return cty.NilType, errors.New("keys and searchset must be of the same type")
   342  		}
   343  
   344  		// the return type is based on args[0] (values)
   345  		return args[0].Type(), nil
   346  	},
   347  	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
   348  		if !args[0].IsKnown() {
   349  			return cty.UnknownVal(cty.List(retType.ElementType())), nil
   350  		}
   351  
   352  		if args[0].LengthInt() != args[1].LengthInt() {
   353  			return cty.ListValEmpty(retType.ElementType()), errors.New("length of keys and values should be equal")
   354  		}
   355  
   356  		output := make([]cty.Value, 0)
   357  		values := args[0]
   358  
   359  		// Keys and searchset must be the same type.
   360  		// We can skip error checking here because we've already verified that
   361  		// they can be unified in the Type function
   362  		ty, _ := convert.UnifyUnsafe([]cty.Type{args[1].Type(), args[2].Type()})
   363  		keys, _ := convert.Convert(args[1], ty)
   364  		searchset, _ := convert.Convert(args[2], ty)
   365  
   366  		// if searchset is empty, return an empty list.
   367  		if searchset.LengthInt() == 0 {
   368  			return cty.ListValEmpty(retType.ElementType()), nil
   369  		}
   370  
   371  		if !values.IsWhollyKnown() || !keys.IsWhollyKnown() {
   372  			return cty.UnknownVal(retType), nil
   373  		}
   374  
   375  		i := 0
   376  		for it := keys.ElementIterator(); it.Next(); {
   377  			_, key := it.Element()
   378  			for iter := searchset.ElementIterator(); iter.Next(); {
   379  				_, search := iter.Element()
   380  				eq, err := stdlib.Equal(key, search)
   381  				if err != nil {
   382  					return cty.NilVal, err
   383  				}
   384  				if !eq.IsKnown() {
   385  					return cty.ListValEmpty(retType.ElementType()), nil
   386  				}
   387  				if eq.True() {
   388  					v := values.Index(cty.NumberIntVal(int64(i)))
   389  					output = append(output, v)
   390  					break
   391  				}
   392  			}
   393  			i++
   394  		}
   395  
   396  		// if we haven't matched any key, then output is an empty list.
   397  		if len(output) == 0 {
   398  			return cty.ListValEmpty(retType.ElementType()), nil
   399  		}
   400  		return cty.ListVal(output), nil
   401  	},
   402  })
   403  
   404  // OneFunc returns either the first element of a one-element list, or null
   405  // if given a zero-element list.
   406  var OneFunc = function.New(&function.Spec{
   407  	Params: []function.Parameter{
   408  		{
   409  			Name: "list",
   410  			Type: cty.DynamicPseudoType,
   411  		},
   412  	},
   413  	Type: func(args []cty.Value) (cty.Type, error) {
   414  		ty := args[0].Type()
   415  		switch {
   416  		case ty.IsListType() || ty.IsSetType():
   417  			return ty.ElementType(), nil
   418  		case ty.IsTupleType():
   419  			etys := ty.TupleElementTypes()
   420  			switch len(etys) {
   421  			case 0:
   422  				// No specific type information, so we'll ultimately return
   423  				// a null value of unknown type.
   424  				return cty.DynamicPseudoType, nil
   425  			case 1:
   426  				return etys[0], nil
   427  			}
   428  		}
   429  		return cty.NilType, function.NewArgErrorf(0, "must be a list, set, or tuple value with either zero or one elements")
   430  	},
   431  	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
   432  		val := args[0]
   433  		ty := val.Type()
   434  
   435  		// Our parameter spec above doesn't set AllowUnknown or AllowNull,
   436  		// so we can assume our top-level collection is both known and non-null
   437  		// in here.
   438  
   439  		switch {
   440  		case ty.IsListType() || ty.IsSetType():
   441  			lenVal := val.Length()
   442  			if !lenVal.IsKnown() {
   443  				return cty.UnknownVal(retType), nil
   444  			}
   445  			var l int
   446  			err := gocty.FromCtyValue(lenVal, &l)
   447  			if err != nil {
   448  				// It would be very strange to get here, because that would
   449  				// suggest that the length is either not a number or isn't
   450  				// an integer, which would suggest a bug in cty.
   451  				return cty.NilVal, fmt.Errorf("invalid collection length: %s", err)
   452  			}
   453  			switch l {
   454  			case 0:
   455  				return cty.NullVal(retType), nil
   456  			case 1:
   457  				var ret cty.Value
   458  				// We'll use an iterator here because that works for both lists
   459  				// and sets, whereas indexing directly would only work for lists.
   460  				// Since we've just checked the length, we should only actually
   461  				// run this loop body once.
   462  				for it := val.ElementIterator(); it.Next(); {
   463  					_, ret = it.Element()
   464  				}
   465  				return ret, nil
   466  			}
   467  		case ty.IsTupleType():
   468  			etys := ty.TupleElementTypes()
   469  			switch len(etys) {
   470  			case 0:
   471  				return cty.NullVal(retType), nil
   472  			case 1:
   473  				ret := val.Index(cty.NumberIntVal(0))
   474  				return ret, nil
   475  			}
   476  		}
   477  		return cty.NilVal, function.NewArgErrorf(0, "must be a list, set, or tuple value with either zero or one elements")
   478  	},
   479  })
   480  
   481  // SumFunc constructs a function that returns the sum of all
   482  // numbers provided in a list
   483  var SumFunc = function.New(&function.Spec{
   484  	Params: []function.Parameter{
   485  		{
   486  			Name: "list",
   487  			Type: cty.DynamicPseudoType,
   488  		},
   489  	},
   490  	Type: function.StaticReturnType(cty.Number),
   491  	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
   492  
   493  		if !args[0].CanIterateElements() {
   494  			return cty.NilVal, function.NewArgErrorf(0, "cannot sum noniterable")
   495  		}
   496  
   497  		if args[0].LengthInt() == 0 { // Easy path
   498  			return cty.NilVal, function.NewArgErrorf(0, "cannot sum an empty list")
   499  		}
   500  
   501  		arg := args[0].AsValueSlice()
   502  		ty := args[0].Type()
   503  
   504  		if !ty.IsListType() && !ty.IsSetType() && !ty.IsTupleType() {
   505  			return cty.NilVal, function.NewArgErrorf(0, fmt.Sprintf("argument must be list, set, or tuple. Received %s", ty.FriendlyName()))
   506  		}
   507  
   508  		if !args[0].IsWhollyKnown() {
   509  			return cty.UnknownVal(cty.Number), nil
   510  		}
   511  
   512  		// big.Float.Add can panic if the input values are opposing infinities,
   513  		// so we must catch that here in order to remain within
   514  		// the cty Function abstraction.
   515  		defer func() {
   516  			if r := recover(); r != nil {
   517  				if _, ok := r.(big.ErrNaN); ok {
   518  					ret = cty.NilVal
   519  					err = fmt.Errorf("can't compute sum of opposing infinities")
   520  				} else {
   521  					// not a panic we recognize
   522  					panic(r)
   523  				}
   524  			}
   525  		}()
   526  
   527  		s := arg[0]
   528  		if s.IsNull() {
   529  			return cty.NilVal, function.NewArgErrorf(0, "argument must be list, set, or tuple of number values")
   530  		}
   531  		for _, v := range arg[1:] {
   532  			if v.IsNull() {
   533  				return cty.NilVal, function.NewArgErrorf(0, "argument must be list, set, or tuple of number values")
   534  			}
   535  			v, err = convert.Convert(v, cty.Number)
   536  			if err != nil {
   537  				return cty.NilVal, function.NewArgErrorf(0, "argument must be list, set, or tuple of number values")
   538  			}
   539  			s = s.Add(v)
   540  		}
   541  
   542  		return s, nil
   543  	},
   544  })
   545  
   546  // TransposeFunc constructs a function that takes a map of lists of strings and
   547  // swaps the keys and values to produce a new map of lists of strings.
   548  var TransposeFunc = function.New(&function.Spec{
   549  	Params: []function.Parameter{
   550  		{
   551  			Name: "values",
   552  			Type: cty.Map(cty.List(cty.String)),
   553  		},
   554  	},
   555  	Type: function.StaticReturnType(cty.Map(cty.List(cty.String))),
   556  	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
   557  		inputMap := args[0]
   558  		if !inputMap.IsWhollyKnown() {
   559  			return cty.UnknownVal(retType), nil
   560  		}
   561  
   562  		outputMap := make(map[string]cty.Value)
   563  		tmpMap := make(map[string][]string)
   564  
   565  		for it := inputMap.ElementIterator(); it.Next(); {
   566  			inKey, inVal := it.Element()
   567  			for iter := inVal.ElementIterator(); iter.Next(); {
   568  				_, val := iter.Element()
   569  				if !val.Type().Equals(cty.String) {
   570  					return cty.MapValEmpty(cty.List(cty.String)), errors.New("input must be a map of lists of strings")
   571  				}
   572  
   573  				outKey := val.AsString()
   574  				if _, ok := tmpMap[outKey]; !ok {
   575  					tmpMap[outKey] = make([]string, 0)
   576  				}
   577  				outVal := tmpMap[outKey]
   578  				outVal = append(outVal, inKey.AsString())
   579  				sort.Strings(outVal)
   580  				tmpMap[outKey] = outVal
   581  			}
   582  		}
   583  
   584  		for outKey, outVal := range tmpMap {
   585  			values := make([]cty.Value, 0)
   586  			for _, v := range outVal {
   587  				values = append(values, cty.StringVal(v))
   588  			}
   589  			outputMap[outKey] = cty.ListVal(values)
   590  		}
   591  
   592  		if len(outputMap) == 0 {
   593  			return cty.MapValEmpty(cty.List(cty.String)), nil
   594  		}
   595  
   596  		return cty.MapVal(outputMap), nil
   597  	},
   598  })
   599  
   600  // ListFunc constructs a function that takes an arbitrary number of arguments
   601  // and returns a list containing those values in the same order.
   602  //
   603  // This function is deprecated in Terraform v0.12
   604  var ListFunc = function.New(&function.Spec{
   605  	Params: []function.Parameter{},
   606  	VarParam: &function.Parameter{
   607  		Name:             "vals",
   608  		Type:             cty.DynamicPseudoType,
   609  		AllowUnknown:     true,
   610  		AllowDynamicType: true,
   611  		AllowNull:        true,
   612  	},
   613  	Type: func(args []cty.Value) (ret cty.Type, err error) {
   614  		return cty.DynamicPseudoType, fmt.Errorf("the \"list\" function was deprecated in Terraform v0.12 and is no longer available; use tolist([ ... ]) syntax to write a literal list")
   615  	},
   616  	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
   617  		return cty.DynamicVal, fmt.Errorf("the \"list\" function was deprecated in Terraform v0.12 and is no longer available; use tolist([ ... ]) syntax to write a literal list")
   618  	},
   619  })
   620  
   621  // MapFunc constructs a function that takes an even number of arguments and
   622  // returns a map whose elements are constructed from consecutive pairs of arguments.
   623  //
   624  // This function is deprecated in Terraform v0.12
   625  var MapFunc = function.New(&function.Spec{
   626  	Params: []function.Parameter{},
   627  	VarParam: &function.Parameter{
   628  		Name:             "vals",
   629  		Type:             cty.DynamicPseudoType,
   630  		AllowUnknown:     true,
   631  		AllowDynamicType: true,
   632  		AllowNull:        true,
   633  	},
   634  	Type: func(args []cty.Value) (ret cty.Type, err error) {
   635  		return cty.DynamicPseudoType, fmt.Errorf("the \"map\" function was deprecated in Terraform v0.12 and is no longer available; use tomap({ ... }) syntax to write a literal map")
   636  	},
   637  	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
   638  		return cty.DynamicVal, fmt.Errorf("the \"map\" function was deprecated in Terraform v0.12 and is no longer available; use tomap({ ... }) syntax to write a literal map")
   639  	},
   640  })
   641  
   642  // Length returns the number of elements in the given collection or number of
   643  // Unicode characters in the given string.
   644  func Length(collection cty.Value) (cty.Value, error) {
   645  	return LengthFunc.Call([]cty.Value{collection})
   646  }
   647  
   648  // AllTrue returns true if all elements of the list are true. If the list is empty,
   649  // return true.
   650  func AllTrue(collection cty.Value) (cty.Value, error) {
   651  	return AllTrueFunc.Call([]cty.Value{collection})
   652  }
   653  
   654  // AnyTrue returns true if any element of the list is true. If the list is empty,
   655  // return false.
   656  func AnyTrue(collection cty.Value) (cty.Value, error) {
   657  	return AnyTrueFunc.Call([]cty.Value{collection})
   658  }
   659  
   660  // Coalesce takes any number of arguments and returns the first one that isn't empty.
   661  func Coalesce(args ...cty.Value) (cty.Value, error) {
   662  	return CoalesceFunc.Call(args)
   663  }
   664  
   665  // Index finds the element index for a given value in a list.
   666  func Index(list, value cty.Value) (cty.Value, error) {
   667  	return IndexFunc.Call([]cty.Value{list, value})
   668  }
   669  
   670  // List takes any number of list arguments and returns a list containing those
   671  //
   672  //	values in the same order.
   673  func List(args ...cty.Value) (cty.Value, error) {
   674  	return ListFunc.Call(args)
   675  }
   676  
   677  // Lookup performs a dynamic lookup into a map.
   678  // There are two required arguments, map and key, plus an optional default,
   679  // which is a value to return if no key is found in map.
   680  func Lookup(args ...cty.Value) (cty.Value, error) {
   681  	return LookupFunc.Call(args)
   682  }
   683  
   684  // Map takes an even number of arguments and returns a map whose elements are constructed
   685  // from consecutive pairs of arguments.
   686  func Map(args ...cty.Value) (cty.Value, error) {
   687  	return MapFunc.Call(args)
   688  }
   689  
   690  // Matchkeys constructs a new list by taking a subset of elements from one list
   691  // whose indexes match the corresponding indexes of values in another list.
   692  func Matchkeys(values, keys, searchset cty.Value) (cty.Value, error) {
   693  	return MatchkeysFunc.Call([]cty.Value{values, keys, searchset})
   694  }
   695  
   696  // One returns either the first element of a one-element list, or null
   697  // if given a zero-element list..
   698  func One(list cty.Value) (cty.Value, error) {
   699  	return OneFunc.Call([]cty.Value{list})
   700  }
   701  
   702  // Sum adds numbers in a list, set, or tuple
   703  func Sum(list cty.Value) (cty.Value, error) {
   704  	return SumFunc.Call([]cty.Value{list})
   705  }
   706  
   707  // Transpose takes a map of lists of strings and swaps the keys and values to
   708  // produce a new map of lists of strings.
   709  func Transpose(values cty.Value) (cty.Value, error) {
   710  	return TransposeFunc.Call([]cty.Value{values})
   711  }