github.com/hashicorp/hcl/v2@v2.20.0/hcldec/spec.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package hcldec
     5  
     6  import (
     7  	"bytes"
     8  	"fmt"
     9  	"sort"
    10  
    11  	"github.com/hashicorp/hcl/v2"
    12  	"github.com/hashicorp/hcl/v2/ext/customdecode"
    13  	"github.com/zclconf/go-cty/cty"
    14  	"github.com/zclconf/go-cty/cty/convert"
    15  	"github.com/zclconf/go-cty/cty/function"
    16  )
    17  
    18  // A Spec is a description of how to decode a hcl.Body to a cty.Value.
    19  //
    20  // The various other types in this package whose names end in "Spec" are
    21  // the spec implementations. The most common top-level spec is ObjectSpec,
    22  // which decodes body content into a cty.Value of an object type.
    23  type Spec interface {
    24  	// Perform the decode operation on the given body, in the context of
    25  	// the given block (which might be null), using the given eval context.
    26  	//
    27  	// "block" is provided only by the nested calls performed by the spec
    28  	// types that work on block bodies.
    29  	decode(content *hcl.BodyContent, blockLabels []blockLabel, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics)
    30  
    31  	// Return the cty.Type that should be returned when decoding a body with
    32  	// this spec.
    33  	impliedType() cty.Type
    34  
    35  	// Call the given callback once for each of the nested specs that would
    36  	// get decoded with the same body and block as the receiver. This should
    37  	// not descend into the nested specs used when decoding blocks.
    38  	visitSameBodyChildren(cb visitFunc)
    39  
    40  	// Determine the source range of the value that would be returned for the
    41  	// spec in the given content, in the context of the given block
    42  	// (which might be null). If the corresponding item is missing, return
    43  	// a place where it might be inserted.
    44  	sourceRange(content *hcl.BodyContent, blockLabels []blockLabel) hcl.Range
    45  }
    46  
    47  type visitFunc func(spec Spec)
    48  
    49  // An ObjectSpec is a Spec that produces a cty.Value of an object type whose
    50  // attributes correspond to the keys of the spec map.
    51  type ObjectSpec map[string]Spec
    52  
    53  // attrSpec is implemented by specs that require attributes from the body.
    54  type attrSpec interface {
    55  	attrSchemata() []hcl.AttributeSchema
    56  }
    57  
    58  // blockSpec is implemented by specs that require blocks from the body.
    59  type blockSpec interface {
    60  	blockHeaderSchemata() []hcl.BlockHeaderSchema
    61  	nestedSpec() Spec
    62  }
    63  
    64  // specNeedingVariables is implemented by specs that can use variables
    65  // from the EvalContext, to declare which variables they need.
    66  type specNeedingVariables interface {
    67  	variablesNeeded(content *hcl.BodyContent) []hcl.Traversal
    68  }
    69  
    70  // UnknownBody can be optionally implemented by an hcl.Body instance which may
    71  // be entirely unknown.
    72  type UnknownBody interface {
    73  	Unknown() bool
    74  }
    75  
    76  func (s ObjectSpec) visitSameBodyChildren(cb visitFunc) {
    77  	for _, c := range s {
    78  		cb(c)
    79  	}
    80  }
    81  
    82  func (s ObjectSpec) decode(content *hcl.BodyContent, blockLabels []blockLabel, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
    83  	vals := make(map[string]cty.Value, len(s))
    84  	var diags hcl.Diagnostics
    85  
    86  	for k, spec := range s {
    87  		var kd hcl.Diagnostics
    88  		vals[k], kd = spec.decode(content, blockLabels, ctx)
    89  		diags = append(diags, kd...)
    90  	}
    91  
    92  	return cty.ObjectVal(vals), diags
    93  }
    94  
    95  func (s ObjectSpec) impliedType() cty.Type {
    96  	if len(s) == 0 {
    97  		return cty.EmptyObject
    98  	}
    99  
   100  	attrTypes := make(map[string]cty.Type)
   101  	for k, childSpec := range s {
   102  		attrTypes[k] = childSpec.impliedType()
   103  	}
   104  	return cty.Object(attrTypes)
   105  }
   106  
   107  func (s ObjectSpec) sourceRange(content *hcl.BodyContent, blockLabels []blockLabel) hcl.Range {
   108  	// This is not great, but the best we can do. In practice, it's rather
   109  	// strange to ask for the source range of an entire top-level body, since
   110  	// that's already readily available to the caller.
   111  	return content.MissingItemRange
   112  }
   113  
   114  // A TupleSpec is a Spec that produces a cty.Value of a tuple type whose
   115  // elements correspond to the elements of the spec slice.
   116  type TupleSpec []Spec
   117  
   118  func (s TupleSpec) visitSameBodyChildren(cb visitFunc) {
   119  	for _, c := range s {
   120  		cb(c)
   121  	}
   122  }
   123  
   124  func (s TupleSpec) decode(content *hcl.BodyContent, blockLabels []blockLabel, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
   125  	vals := make([]cty.Value, len(s))
   126  	var diags hcl.Diagnostics
   127  
   128  	for i, spec := range s {
   129  		var ed hcl.Diagnostics
   130  		vals[i], ed = spec.decode(content, blockLabels, ctx)
   131  		diags = append(diags, ed...)
   132  	}
   133  
   134  	return cty.TupleVal(vals), diags
   135  }
   136  
   137  func (s TupleSpec) impliedType() cty.Type {
   138  	if len(s) == 0 {
   139  		return cty.EmptyTuple
   140  	}
   141  
   142  	attrTypes := make([]cty.Type, len(s))
   143  	for i, childSpec := range s {
   144  		attrTypes[i] = childSpec.impliedType()
   145  	}
   146  	return cty.Tuple(attrTypes)
   147  }
   148  
   149  func (s TupleSpec) sourceRange(content *hcl.BodyContent, blockLabels []blockLabel) hcl.Range {
   150  	// This is not great, but the best we can do. In practice, it's rather
   151  	// strange to ask for the source range of an entire top-level body, since
   152  	// that's already readily available to the caller.
   153  	return content.MissingItemRange
   154  }
   155  
   156  // An AttrSpec is a Spec that evaluates a particular attribute expression in
   157  // the body and returns its resulting value converted to the requested type,
   158  // or produces a diagnostic if the type is incorrect.
   159  type AttrSpec struct {
   160  	Name     string
   161  	Type     cty.Type
   162  	Required bool
   163  }
   164  
   165  func (s *AttrSpec) visitSameBodyChildren(cb visitFunc) {
   166  	// leaf node
   167  }
   168  
   169  // specNeedingVariables implementation
   170  func (s *AttrSpec) variablesNeeded(content *hcl.BodyContent) []hcl.Traversal {
   171  	attr, exists := content.Attributes[s.Name]
   172  	if !exists {
   173  		return nil
   174  	}
   175  
   176  	return attr.Expr.Variables()
   177  }
   178  
   179  // attrSpec implementation
   180  func (s *AttrSpec) attrSchemata() []hcl.AttributeSchema {
   181  	return []hcl.AttributeSchema{
   182  		{
   183  			Name:     s.Name,
   184  			Required: s.Required,
   185  		},
   186  	}
   187  }
   188  
   189  func (s *AttrSpec) sourceRange(content *hcl.BodyContent, blockLabels []blockLabel) hcl.Range {
   190  	attr, exists := content.Attributes[s.Name]
   191  	if !exists {
   192  		return content.MissingItemRange
   193  	}
   194  
   195  	return attr.Expr.Range()
   196  }
   197  
   198  func (s *AttrSpec) decode(content *hcl.BodyContent, blockLabels []blockLabel, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
   199  	attr, exists := content.Attributes[s.Name]
   200  	if !exists {
   201  		// We don't need to check required and emit a diagnostic here, because
   202  		// that would already have happened when building "content".
   203  		return cty.NullVal(s.Type.WithoutOptionalAttributesDeep()), nil
   204  	}
   205  
   206  	if decodeFn := customdecode.CustomExpressionDecoderForType(s.Type); decodeFn != nil {
   207  		v, diags := decodeFn(attr.Expr, ctx)
   208  		if v == cty.NilVal {
   209  			v = cty.UnknownVal(s.Type.WithoutOptionalAttributesDeep())
   210  		}
   211  		return v, diags
   212  	}
   213  
   214  	val, diags := attr.Expr.Value(ctx)
   215  
   216  	convVal, err := convert.Convert(val, s.Type)
   217  	if err != nil {
   218  		diags = append(diags, &hcl.Diagnostic{
   219  			Severity: hcl.DiagError,
   220  			Summary:  "Incorrect attribute value type",
   221  			Detail: fmt.Sprintf(
   222  				"Inappropriate value for attribute %q: %s.",
   223  				s.Name, err.Error(),
   224  			),
   225  			Subject:     attr.Expr.Range().Ptr(),
   226  			Context:     hcl.RangeBetween(attr.NameRange, attr.Expr.Range()).Ptr(),
   227  			Expression:  attr.Expr,
   228  			EvalContext: ctx,
   229  		})
   230  		// We'll return an unknown value of the _correct_ type so that the
   231  		// incomplete result can still be used for some analysis use-cases.
   232  		val = cty.UnknownVal(s.Type.WithoutOptionalAttributesDeep())
   233  	} else {
   234  		val = convVal
   235  	}
   236  
   237  	return val, diags
   238  }
   239  
   240  func (s *AttrSpec) impliedType() cty.Type {
   241  	return s.Type
   242  }
   243  
   244  // A LiteralSpec is a Spec that produces the given literal value, ignoring
   245  // the given body.
   246  type LiteralSpec struct {
   247  	Value cty.Value
   248  }
   249  
   250  func (s *LiteralSpec) visitSameBodyChildren(cb visitFunc) {
   251  	// leaf node
   252  }
   253  
   254  func (s *LiteralSpec) decode(content *hcl.BodyContent, blockLabels []blockLabel, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
   255  	return s.Value, nil
   256  }
   257  
   258  func (s *LiteralSpec) impliedType() cty.Type {
   259  	return s.Value.Type()
   260  }
   261  
   262  func (s *LiteralSpec) sourceRange(content *hcl.BodyContent, blockLabels []blockLabel) hcl.Range {
   263  	// No sensible range to return for a literal, so the caller had better
   264  	// ensure it doesn't cause any diagnostics.
   265  	return hcl.Range{
   266  		Filename: "<unknown>",
   267  	}
   268  }
   269  
   270  // An ExprSpec is a Spec that evaluates the given expression, ignoring the
   271  // given body.
   272  type ExprSpec struct {
   273  	Expr hcl.Expression
   274  }
   275  
   276  func (s *ExprSpec) visitSameBodyChildren(cb visitFunc) {
   277  	// leaf node
   278  }
   279  
   280  // specNeedingVariables implementation
   281  func (s *ExprSpec) variablesNeeded(content *hcl.BodyContent) []hcl.Traversal {
   282  	return s.Expr.Variables()
   283  }
   284  
   285  func (s *ExprSpec) decode(content *hcl.BodyContent, blockLabels []blockLabel, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
   286  	return s.Expr.Value(ctx)
   287  }
   288  
   289  func (s *ExprSpec) impliedType() cty.Type {
   290  	// We can't know the type of our expression until we evaluate it
   291  	return cty.DynamicPseudoType
   292  }
   293  
   294  func (s *ExprSpec) sourceRange(content *hcl.BodyContent, blockLabels []blockLabel) hcl.Range {
   295  	return s.Expr.Range()
   296  }
   297  
   298  // A BlockSpec is a Spec that produces a cty.Value by decoding the contents
   299  // of a single nested block of a given type, using a nested spec.
   300  //
   301  // If the Required flag is not set, the nested block may be omitted, in which
   302  // case a null value is produced. If it _is_ set, an error diagnostic is
   303  // produced if there are no nested blocks of the given type.
   304  type BlockSpec struct {
   305  	TypeName string
   306  	Nested   Spec
   307  	Required bool
   308  }
   309  
   310  func (s *BlockSpec) visitSameBodyChildren(cb visitFunc) {
   311  	// leaf node ("Nested" does not use the same body)
   312  }
   313  
   314  // blockSpec implementation
   315  func (s *BlockSpec) blockHeaderSchemata() []hcl.BlockHeaderSchema {
   316  	return []hcl.BlockHeaderSchema{
   317  		{
   318  			Type:       s.TypeName,
   319  			LabelNames: findLabelSpecs(s.Nested),
   320  		},
   321  	}
   322  }
   323  
   324  // blockSpec implementation
   325  func (s *BlockSpec) nestedSpec() Spec {
   326  	return s.Nested
   327  }
   328  
   329  // specNeedingVariables implementation
   330  func (s *BlockSpec) variablesNeeded(content *hcl.BodyContent) []hcl.Traversal {
   331  	var childBlock *hcl.Block
   332  	for _, candidate := range content.Blocks {
   333  		if candidate.Type != s.TypeName {
   334  			continue
   335  		}
   336  
   337  		childBlock = candidate
   338  		break
   339  	}
   340  
   341  	if childBlock == nil {
   342  		return nil
   343  	}
   344  
   345  	return Variables(childBlock.Body, s.Nested)
   346  }
   347  
   348  func (s *BlockSpec) decode(content *hcl.BodyContent, blockLabels []blockLabel, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
   349  	var diags hcl.Diagnostics
   350  
   351  	var childBlock *hcl.Block
   352  	for _, candidate := range content.Blocks {
   353  		if candidate.Type != s.TypeName {
   354  			continue
   355  		}
   356  
   357  		if childBlock != nil {
   358  			diags = append(diags, &hcl.Diagnostic{
   359  				Severity: hcl.DiagError,
   360  				Summary:  fmt.Sprintf("Duplicate %s block", s.TypeName),
   361  				Detail: fmt.Sprintf(
   362  					"Only one block of type %q is allowed. Previous definition was at %s.",
   363  					s.TypeName, childBlock.DefRange.String(),
   364  				),
   365  				Subject: &candidate.DefRange,
   366  			})
   367  			break
   368  		}
   369  
   370  		childBlock = candidate
   371  	}
   372  
   373  	if childBlock == nil {
   374  		if s.Required {
   375  			diags = append(diags, &hcl.Diagnostic{
   376  				Severity: hcl.DiagError,
   377  				Summary:  fmt.Sprintf("Missing %s block", s.TypeName),
   378  				Detail: fmt.Sprintf(
   379  					"A block of type %q is required here.", s.TypeName,
   380  				),
   381  				Subject: &content.MissingItemRange,
   382  			})
   383  		}
   384  		return cty.NullVal(s.Nested.impliedType().WithoutOptionalAttributesDeep()), diags
   385  	}
   386  
   387  	if s.Nested == nil {
   388  		panic("BlockSpec with no Nested Spec")
   389  	}
   390  	val, _, childDiags := decode(childBlock.Body, labelsForBlock(childBlock), ctx, s.Nested, false)
   391  	diags = append(diags, childDiags...)
   392  	return val, diags
   393  }
   394  
   395  func (s *BlockSpec) impliedType() cty.Type {
   396  	return s.Nested.impliedType()
   397  }
   398  
   399  func (s *BlockSpec) sourceRange(content *hcl.BodyContent, blockLabels []blockLabel) hcl.Range {
   400  	var childBlock *hcl.Block
   401  	for _, candidate := range content.Blocks {
   402  		if candidate.Type != s.TypeName {
   403  			continue
   404  		}
   405  
   406  		childBlock = candidate
   407  		break
   408  	}
   409  
   410  	if childBlock == nil {
   411  		return content.MissingItemRange
   412  	}
   413  
   414  	return sourceRange(childBlock.Body, labelsForBlock(childBlock), s.Nested)
   415  }
   416  
   417  // A BlockListSpec is a Spec that produces a cty list of the results of
   418  // decoding all of the nested blocks of a given type, using a nested spec.
   419  type BlockListSpec struct {
   420  	TypeName string
   421  	Nested   Spec
   422  	MinItems int
   423  	MaxItems int
   424  }
   425  
   426  func (s *BlockListSpec) visitSameBodyChildren(cb visitFunc) {
   427  	// leaf node ("Nested" does not use the same body)
   428  }
   429  
   430  // blockSpec implementation
   431  func (s *BlockListSpec) blockHeaderSchemata() []hcl.BlockHeaderSchema {
   432  	return []hcl.BlockHeaderSchema{
   433  		{
   434  			Type:       s.TypeName,
   435  			LabelNames: findLabelSpecs(s.Nested),
   436  		},
   437  	}
   438  }
   439  
   440  // blockSpec implementation
   441  func (s *BlockListSpec) nestedSpec() Spec {
   442  	return s.Nested
   443  }
   444  
   445  // specNeedingVariables implementation
   446  func (s *BlockListSpec) variablesNeeded(content *hcl.BodyContent) []hcl.Traversal {
   447  	var ret []hcl.Traversal
   448  
   449  	for _, childBlock := range content.Blocks {
   450  		if childBlock.Type != s.TypeName {
   451  			continue
   452  		}
   453  
   454  		ret = append(ret, Variables(childBlock.Body, s.Nested)...)
   455  	}
   456  
   457  	return ret
   458  }
   459  
   460  func (s *BlockListSpec) decode(content *hcl.BodyContent, blockLabels []blockLabel, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
   461  	var diags hcl.Diagnostics
   462  
   463  	if s.Nested == nil {
   464  		panic("BlockListSpec with no Nested Spec")
   465  	}
   466  
   467  	var elems []cty.Value
   468  	var sourceRanges []hcl.Range
   469  	for _, childBlock := range content.Blocks {
   470  		if childBlock.Type != s.TypeName {
   471  			continue
   472  		}
   473  
   474  		val, _, childDiags := decode(childBlock.Body, labelsForBlock(childBlock), ctx, s.Nested, false)
   475  		diags = append(diags, childDiags...)
   476  
   477  		if u, ok := childBlock.Body.(UnknownBody); ok {
   478  			if u.Unknown() {
   479  				// If any block Body is unknown, then the entire block value
   480  				// must be unknown
   481  				return cty.UnknownVal(s.impliedType().WithoutOptionalAttributesDeep()), diags
   482  			}
   483  		}
   484  
   485  		elems = append(elems, val)
   486  		sourceRanges = append(sourceRanges, sourceRange(childBlock.Body, labelsForBlock(childBlock), s.Nested))
   487  	}
   488  
   489  	if len(elems) < s.MinItems {
   490  		diags = append(diags, &hcl.Diagnostic{
   491  			Severity: hcl.DiagError,
   492  			Summary:  fmt.Sprintf("Insufficient %s blocks", s.TypeName),
   493  			Detail:   fmt.Sprintf("At least %d %q blocks are required.", s.MinItems, s.TypeName),
   494  			Subject:  &content.MissingItemRange,
   495  		})
   496  	} else if s.MaxItems > 0 && len(elems) > s.MaxItems {
   497  		diags = append(diags, &hcl.Diagnostic{
   498  			Severity: hcl.DiagError,
   499  			Summary:  fmt.Sprintf("Too many %s blocks", s.TypeName),
   500  			Detail:   fmt.Sprintf("No more than %d %q blocks are allowed", s.MaxItems, s.TypeName),
   501  			Subject:  &sourceRanges[s.MaxItems],
   502  		})
   503  	}
   504  
   505  	if len(elems) == 0 {
   506  		return cty.ListValEmpty(s.Nested.impliedType()), diags
   507  	}
   508  
   509  	// Since our target is a list, all of the decoded elements must have the
   510  	// same type or cty.ListVal will panic below. Different types can arise
   511  	// if there is an attribute spec of type cty.DynamicPseudoType in the
   512  	// nested spec; all given values must be convertable to a single type
   513  	// in order for the result to be considered valid.
   514  	etys := make([]cty.Type, len(elems))
   515  	for i, v := range elems {
   516  		etys[i] = v.Type()
   517  	}
   518  	ety, convs := convert.UnifyUnsafe(etys)
   519  	if ety == cty.NilType {
   520  		// FIXME: This is a pretty terrible error message.
   521  		diags = append(diags, &hcl.Diagnostic{
   522  			Severity: hcl.DiagError,
   523  			Summary:  fmt.Sprintf("Unconsistent argument types in %s blocks", s.TypeName),
   524  			Detail:   "Corresponding attributes in all blocks of this type must be the same.",
   525  			Subject:  &sourceRanges[0],
   526  		})
   527  		return cty.DynamicVal, diags
   528  	}
   529  	for i, v := range elems {
   530  		if convs[i] != nil {
   531  			newV, err := convs[i](v)
   532  			if err != nil {
   533  				// FIXME: This is a pretty terrible error message.
   534  				diags = append(diags, &hcl.Diagnostic{
   535  					Severity: hcl.DiagError,
   536  					Summary:  fmt.Sprintf("Unconsistent argument types in %s blocks", s.TypeName),
   537  					Detail:   fmt.Sprintf("Block with index %d has inconsistent argument types: %s.", i, err),
   538  					Subject:  &sourceRanges[i],
   539  				})
   540  				// Bail early here so we won't panic below in cty.ListVal
   541  				return cty.DynamicVal, diags
   542  			}
   543  			elems[i] = newV
   544  		}
   545  	}
   546  
   547  	return cty.ListVal(elems), diags
   548  }
   549  
   550  func (s *BlockListSpec) impliedType() cty.Type {
   551  	return cty.List(s.Nested.impliedType())
   552  }
   553  
   554  func (s *BlockListSpec) sourceRange(content *hcl.BodyContent, blockLabels []blockLabel) hcl.Range {
   555  	// We return the source range of the _first_ block of the given type,
   556  	// since they are not guaranteed to form a contiguous range.
   557  
   558  	var childBlock *hcl.Block
   559  	for _, candidate := range content.Blocks {
   560  		if candidate.Type != s.TypeName {
   561  			continue
   562  		}
   563  
   564  		childBlock = candidate
   565  		break
   566  	}
   567  
   568  	if childBlock == nil {
   569  		return content.MissingItemRange
   570  	}
   571  
   572  	return sourceRange(childBlock.Body, labelsForBlock(childBlock), s.Nested)
   573  }
   574  
   575  // A BlockTupleSpec is a Spec that produces a cty tuple of the results of
   576  // decoding all of the nested blocks of a given type, using a nested spec.
   577  //
   578  // This is similar to BlockListSpec, but it permits the nested blocks to have
   579  // different result types in situations where cty.DynamicPseudoType attributes
   580  // are present.
   581  type BlockTupleSpec struct {
   582  	TypeName string
   583  	Nested   Spec
   584  	MinItems int
   585  	MaxItems int
   586  }
   587  
   588  func (s *BlockTupleSpec) visitSameBodyChildren(cb visitFunc) {
   589  	// leaf node ("Nested" does not use the same body)
   590  }
   591  
   592  // blockSpec implementation
   593  func (s *BlockTupleSpec) blockHeaderSchemata() []hcl.BlockHeaderSchema {
   594  	return []hcl.BlockHeaderSchema{
   595  		{
   596  			Type:       s.TypeName,
   597  			LabelNames: findLabelSpecs(s.Nested),
   598  		},
   599  	}
   600  }
   601  
   602  // blockSpec implementation
   603  func (s *BlockTupleSpec) nestedSpec() Spec {
   604  	return s.Nested
   605  }
   606  
   607  // specNeedingVariables implementation
   608  func (s *BlockTupleSpec) variablesNeeded(content *hcl.BodyContent) []hcl.Traversal {
   609  	var ret []hcl.Traversal
   610  
   611  	for _, childBlock := range content.Blocks {
   612  		if childBlock.Type != s.TypeName {
   613  			continue
   614  		}
   615  
   616  		ret = append(ret, Variables(childBlock.Body, s.Nested)...)
   617  	}
   618  
   619  	return ret
   620  }
   621  
   622  func (s *BlockTupleSpec) decode(content *hcl.BodyContent, blockLabels []blockLabel, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
   623  	var diags hcl.Diagnostics
   624  
   625  	if s.Nested == nil {
   626  		panic("BlockListSpec with no Nested Spec")
   627  	}
   628  
   629  	var elems []cty.Value
   630  	var sourceRanges []hcl.Range
   631  	for _, childBlock := range content.Blocks {
   632  		if childBlock.Type != s.TypeName {
   633  			continue
   634  		}
   635  
   636  		val, _, childDiags := decode(childBlock.Body, labelsForBlock(childBlock), ctx, s.Nested, false)
   637  		diags = append(diags, childDiags...)
   638  
   639  		if u, ok := childBlock.Body.(UnknownBody); ok {
   640  			if u.Unknown() {
   641  				// If any block Body is unknown, then the entire block value
   642  				// must be unknown
   643  				return cty.UnknownVal(s.impliedType().WithoutOptionalAttributesDeep()), diags
   644  			}
   645  		}
   646  
   647  		elems = append(elems, val)
   648  		sourceRanges = append(sourceRanges, sourceRange(childBlock.Body, labelsForBlock(childBlock), s.Nested))
   649  	}
   650  
   651  	if len(elems) < s.MinItems {
   652  		diags = append(diags, &hcl.Diagnostic{
   653  			Severity: hcl.DiagError,
   654  			Summary:  fmt.Sprintf("Insufficient %s blocks", s.TypeName),
   655  			Detail:   fmt.Sprintf("At least %d %q blocks are required.", s.MinItems, s.TypeName),
   656  			Subject:  &content.MissingItemRange,
   657  		})
   658  	} else if s.MaxItems > 0 && len(elems) > s.MaxItems {
   659  		diags = append(diags, &hcl.Diagnostic{
   660  			Severity: hcl.DiagError,
   661  			Summary:  fmt.Sprintf("Too many %s blocks", s.TypeName),
   662  			Detail:   fmt.Sprintf("No more than %d %q blocks are allowed", s.MaxItems, s.TypeName),
   663  			Subject:  &sourceRanges[s.MaxItems],
   664  		})
   665  	}
   666  
   667  	if len(elems) == 0 {
   668  		return cty.EmptyTupleVal, diags
   669  	}
   670  
   671  	return cty.TupleVal(elems), diags
   672  }
   673  
   674  func (s *BlockTupleSpec) impliedType() cty.Type {
   675  	// We can't predict our type, because we don't know how many blocks
   676  	// there will be until we decode.
   677  	return cty.DynamicPseudoType
   678  }
   679  
   680  func (s *BlockTupleSpec) sourceRange(content *hcl.BodyContent, blockLabels []blockLabel) hcl.Range {
   681  	// We return the source range of the _first_ block of the given type,
   682  	// since they are not guaranteed to form a contiguous range.
   683  
   684  	var childBlock *hcl.Block
   685  	for _, candidate := range content.Blocks {
   686  		if candidate.Type != s.TypeName {
   687  			continue
   688  		}
   689  
   690  		childBlock = candidate
   691  		break
   692  	}
   693  
   694  	if childBlock == nil {
   695  		return content.MissingItemRange
   696  	}
   697  
   698  	return sourceRange(childBlock.Body, labelsForBlock(childBlock), s.Nested)
   699  }
   700  
   701  // A BlockSetSpec is a Spec that produces a cty set of the results of
   702  // decoding all of the nested blocks of a given type, using a nested spec.
   703  type BlockSetSpec struct {
   704  	TypeName string
   705  	Nested   Spec
   706  	MinItems int
   707  	MaxItems int
   708  }
   709  
   710  func (s *BlockSetSpec) visitSameBodyChildren(cb visitFunc) {
   711  	// leaf node ("Nested" does not use the same body)
   712  }
   713  
   714  // blockSpec implementation
   715  func (s *BlockSetSpec) blockHeaderSchemata() []hcl.BlockHeaderSchema {
   716  	return []hcl.BlockHeaderSchema{
   717  		{
   718  			Type:       s.TypeName,
   719  			LabelNames: findLabelSpecs(s.Nested),
   720  		},
   721  	}
   722  }
   723  
   724  // blockSpec implementation
   725  func (s *BlockSetSpec) nestedSpec() Spec {
   726  	return s.Nested
   727  }
   728  
   729  // specNeedingVariables implementation
   730  func (s *BlockSetSpec) variablesNeeded(content *hcl.BodyContent) []hcl.Traversal {
   731  	var ret []hcl.Traversal
   732  
   733  	for _, childBlock := range content.Blocks {
   734  		if childBlock.Type != s.TypeName {
   735  			continue
   736  		}
   737  
   738  		ret = append(ret, Variables(childBlock.Body, s.Nested)...)
   739  	}
   740  
   741  	return ret
   742  }
   743  
   744  func (s *BlockSetSpec) decode(content *hcl.BodyContent, blockLabels []blockLabel, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
   745  	var diags hcl.Diagnostics
   746  
   747  	if s.Nested == nil {
   748  		panic("BlockSetSpec with no Nested Spec")
   749  	}
   750  
   751  	var elems []cty.Value
   752  	var sourceRanges []hcl.Range
   753  
   754  	for _, childBlock := range content.Blocks {
   755  		if childBlock.Type != s.TypeName {
   756  			continue
   757  		}
   758  
   759  		val, _, childDiags := decode(childBlock.Body, labelsForBlock(childBlock), ctx, s.Nested, false)
   760  		diags = append(diags, childDiags...)
   761  
   762  		if u, ok := childBlock.Body.(UnknownBody); ok {
   763  			if u.Unknown() {
   764  				// If any block Body is unknown, then the entire block value
   765  				// must be unknown
   766  				return cty.UnknownVal(s.impliedType().WithoutOptionalAttributesDeep()), diags
   767  			}
   768  		}
   769  
   770  		elems = append(elems, val)
   771  		sourceRanges = append(sourceRanges, sourceRange(childBlock.Body, labelsForBlock(childBlock), s.Nested))
   772  	}
   773  
   774  	if len(elems) < s.MinItems {
   775  		diags = append(diags, &hcl.Diagnostic{
   776  			Severity: hcl.DiagError,
   777  			Summary:  fmt.Sprintf("Insufficient %s blocks", s.TypeName),
   778  			Detail:   fmt.Sprintf("At least %d %q blocks are required.", s.MinItems, s.TypeName),
   779  			Subject:  &content.MissingItemRange,
   780  		})
   781  	} else if s.MaxItems > 0 && len(elems) > s.MaxItems {
   782  		diags = append(diags, &hcl.Diagnostic{
   783  			Severity: hcl.DiagError,
   784  			Summary:  fmt.Sprintf("Too many %s blocks", s.TypeName),
   785  			Detail:   fmt.Sprintf("No more than %d %q blocks are allowed", s.MaxItems, s.TypeName),
   786  			Subject:  &sourceRanges[s.MaxItems],
   787  		})
   788  	}
   789  
   790  	if len(elems) == 0 {
   791  		return cty.SetValEmpty(s.Nested.impliedType()), diags
   792  	}
   793  
   794  	// Since our target is a set, all of the decoded elements must have the
   795  	// same type or cty.SetVal will panic below. Different types can arise
   796  	// if there is an attribute spec of type cty.DynamicPseudoType in the
   797  	// nested spec; all given values must be convertable to a single type
   798  	// in order for the result to be considered valid.
   799  	etys := make([]cty.Type, len(elems))
   800  	for i, v := range elems {
   801  		etys[i] = v.Type()
   802  	}
   803  	ety, convs := convert.UnifyUnsafe(etys)
   804  	if ety == cty.NilType {
   805  		// FIXME: This is a pretty terrible error message.
   806  		diags = append(diags, &hcl.Diagnostic{
   807  			Severity: hcl.DiagError,
   808  			Summary:  fmt.Sprintf("Unconsistent argument types in %s blocks", s.TypeName),
   809  			Detail:   "Corresponding attributes in all blocks of this type must be the same.",
   810  			Subject:  &sourceRanges[0],
   811  		})
   812  		return cty.DynamicVal, diags
   813  	}
   814  	for i, v := range elems {
   815  		if convs[i] != nil {
   816  			newV, err := convs[i](v)
   817  			if err != nil {
   818  				// FIXME: This is a pretty terrible error message.
   819  				diags = append(diags, &hcl.Diagnostic{
   820  					Severity: hcl.DiagError,
   821  					Summary:  fmt.Sprintf("Unconsistent argument types in %s blocks", s.TypeName),
   822  					Detail:   fmt.Sprintf("Block with index %d has inconsistent argument types: %s.", i, err),
   823  					Subject:  &sourceRanges[i],
   824  				})
   825  				// Bail early here so we won't panic below in cty.ListVal
   826  				return cty.DynamicVal, diags
   827  			}
   828  			elems[i] = newV
   829  		}
   830  	}
   831  
   832  	return cty.SetVal(elems), diags
   833  }
   834  
   835  func (s *BlockSetSpec) impliedType() cty.Type {
   836  	return cty.Set(s.Nested.impliedType())
   837  }
   838  
   839  func (s *BlockSetSpec) sourceRange(content *hcl.BodyContent, blockLabels []blockLabel) hcl.Range {
   840  	// We return the source range of the _first_ block of the given type,
   841  	// since they are not guaranteed to form a contiguous range.
   842  
   843  	var childBlock *hcl.Block
   844  	for _, candidate := range content.Blocks {
   845  		if candidate.Type != s.TypeName {
   846  			continue
   847  		}
   848  
   849  		childBlock = candidate
   850  		break
   851  	}
   852  
   853  	if childBlock == nil {
   854  		return content.MissingItemRange
   855  	}
   856  
   857  	return sourceRange(childBlock.Body, labelsForBlock(childBlock), s.Nested)
   858  }
   859  
   860  // A BlockMapSpec is a Spec that produces a cty map of the results of
   861  // decoding all of the nested blocks of a given type, using a nested spec.
   862  //
   863  // One level of map structure is created for each of the given label names.
   864  // There must be at least one given label name.
   865  type BlockMapSpec struct {
   866  	TypeName   string
   867  	LabelNames []string
   868  	Nested     Spec
   869  }
   870  
   871  func (s *BlockMapSpec) visitSameBodyChildren(cb visitFunc) {
   872  	// leaf node ("Nested" does not use the same body)
   873  }
   874  
   875  // blockSpec implementation
   876  func (s *BlockMapSpec) blockHeaderSchemata() []hcl.BlockHeaderSchema {
   877  	return []hcl.BlockHeaderSchema{
   878  		{
   879  			Type:       s.TypeName,
   880  			LabelNames: append(s.LabelNames, findLabelSpecs(s.Nested)...),
   881  		},
   882  	}
   883  }
   884  
   885  // blockSpec implementation
   886  func (s *BlockMapSpec) nestedSpec() Spec {
   887  	return s.Nested
   888  }
   889  
   890  // specNeedingVariables implementation
   891  func (s *BlockMapSpec) variablesNeeded(content *hcl.BodyContent) []hcl.Traversal {
   892  	var ret []hcl.Traversal
   893  
   894  	for _, childBlock := range content.Blocks {
   895  		if childBlock.Type != s.TypeName {
   896  			continue
   897  		}
   898  
   899  		ret = append(ret, Variables(childBlock.Body, s.Nested)...)
   900  	}
   901  
   902  	return ret
   903  }
   904  
   905  func (s *BlockMapSpec) decode(content *hcl.BodyContent, blockLabels []blockLabel, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
   906  	var diags hcl.Diagnostics
   907  
   908  	if s.Nested == nil {
   909  		panic("BlockMapSpec with no Nested Spec")
   910  	}
   911  	if ImpliedType(s).HasDynamicTypes() {
   912  		panic("cty.DynamicPseudoType attributes may not be used inside a BlockMapSpec")
   913  	}
   914  
   915  	elems := map[string]interface{}{}
   916  	for _, childBlock := range content.Blocks {
   917  		if childBlock.Type != s.TypeName {
   918  			continue
   919  		}
   920  
   921  		if u, ok := childBlock.Body.(UnknownBody); ok {
   922  			if u.Unknown() {
   923  				// If any block Body is unknown, then the entire block value
   924  				// must be unknown
   925  				return cty.UnknownVal(s.impliedType().WithoutOptionalAttributesDeep()), diags
   926  			}
   927  		}
   928  
   929  		childLabels := labelsForBlock(childBlock)
   930  		val, _, childDiags := decode(childBlock.Body, childLabels[len(s.LabelNames):], ctx, s.Nested, false)
   931  		targetMap := elems
   932  		for _, key := range childBlock.Labels[:len(s.LabelNames)-1] {
   933  			if _, exists := targetMap[key]; !exists {
   934  				targetMap[key] = make(map[string]interface{})
   935  			}
   936  			targetMap = targetMap[key].(map[string]interface{})
   937  		}
   938  
   939  		diags = append(diags, childDiags...)
   940  
   941  		key := childBlock.Labels[len(s.LabelNames)-1]
   942  		if _, exists := targetMap[key]; exists {
   943  			labelsBuf := bytes.Buffer{}
   944  			for _, label := range childBlock.Labels {
   945  				fmt.Fprintf(&labelsBuf, " %q", label)
   946  			}
   947  			diags = append(diags, &hcl.Diagnostic{
   948  				Severity: hcl.DiagError,
   949  				Summary:  fmt.Sprintf("Duplicate %s block", s.TypeName),
   950  				Detail: fmt.Sprintf(
   951  					"A block for %s%s was already defined. The %s labels must be unique.",
   952  					s.TypeName, labelsBuf.String(), s.TypeName,
   953  				),
   954  				Subject: &childBlock.DefRange,
   955  			})
   956  			continue
   957  		}
   958  
   959  		targetMap[key] = val
   960  	}
   961  
   962  	if len(elems) == 0 {
   963  		return cty.MapValEmpty(s.Nested.impliedType()), diags
   964  	}
   965  
   966  	var ctyMap func(map[string]interface{}, int) cty.Value
   967  	ctyMap = func(raw map[string]interface{}, depth int) cty.Value {
   968  		vals := make(map[string]cty.Value, len(raw))
   969  		if depth == 1 {
   970  			for k, v := range raw {
   971  				vals[k] = v.(cty.Value)
   972  			}
   973  		} else {
   974  			for k, v := range raw {
   975  				vals[k] = ctyMap(v.(map[string]interface{}), depth-1)
   976  			}
   977  		}
   978  		return cty.MapVal(vals)
   979  	}
   980  
   981  	return ctyMap(elems, len(s.LabelNames)), diags
   982  }
   983  
   984  func (s *BlockMapSpec) impliedType() cty.Type {
   985  	ret := s.Nested.impliedType()
   986  	for _ = range s.LabelNames {
   987  		ret = cty.Map(ret)
   988  	}
   989  	return ret
   990  }
   991  
   992  func (s *BlockMapSpec) sourceRange(content *hcl.BodyContent, blockLabels []blockLabel) hcl.Range {
   993  	// We return the source range of the _first_ block of the given type,
   994  	// since they are not guaranteed to form a contiguous range.
   995  
   996  	var childBlock *hcl.Block
   997  	for _, candidate := range content.Blocks {
   998  		if candidate.Type != s.TypeName {
   999  			continue
  1000  		}
  1001  
  1002  		childBlock = candidate
  1003  		break
  1004  	}
  1005  
  1006  	if childBlock == nil {
  1007  		return content.MissingItemRange
  1008  	}
  1009  
  1010  	return sourceRange(childBlock.Body, labelsForBlock(childBlock), s.Nested)
  1011  }
  1012  
  1013  // A BlockObjectSpec is a Spec that produces a cty object of the results of
  1014  // decoding all of the nested blocks of a given type, using a nested spec.
  1015  //
  1016  // One level of object structure is created for each of the given label names.
  1017  // There must be at least one given label name.
  1018  //
  1019  // This is similar to BlockMapSpec, but it permits the nested blocks to have
  1020  // different result types in situations where cty.DynamicPseudoType attributes
  1021  // are present.
  1022  type BlockObjectSpec struct {
  1023  	TypeName   string
  1024  	LabelNames []string
  1025  	Nested     Spec
  1026  }
  1027  
  1028  func (s *BlockObjectSpec) visitSameBodyChildren(cb visitFunc) {
  1029  	// leaf node ("Nested" does not use the same body)
  1030  }
  1031  
  1032  // blockSpec implementation
  1033  func (s *BlockObjectSpec) blockHeaderSchemata() []hcl.BlockHeaderSchema {
  1034  	return []hcl.BlockHeaderSchema{
  1035  		{
  1036  			Type:       s.TypeName,
  1037  			LabelNames: append(s.LabelNames, findLabelSpecs(s.Nested)...),
  1038  		},
  1039  	}
  1040  }
  1041  
  1042  // blockSpec implementation
  1043  func (s *BlockObjectSpec) nestedSpec() Spec {
  1044  	return s.Nested
  1045  }
  1046  
  1047  // specNeedingVariables implementation
  1048  func (s *BlockObjectSpec) variablesNeeded(content *hcl.BodyContent) []hcl.Traversal {
  1049  	var ret []hcl.Traversal
  1050  
  1051  	for _, childBlock := range content.Blocks {
  1052  		if childBlock.Type != s.TypeName {
  1053  			continue
  1054  		}
  1055  
  1056  		ret = append(ret, Variables(childBlock.Body, s.Nested)...)
  1057  	}
  1058  
  1059  	return ret
  1060  }
  1061  
  1062  func (s *BlockObjectSpec) decode(content *hcl.BodyContent, blockLabels []blockLabel, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
  1063  	var diags hcl.Diagnostics
  1064  
  1065  	if s.Nested == nil {
  1066  		panic("BlockObjectSpec with no Nested Spec")
  1067  	}
  1068  
  1069  	elems := map[string]interface{}{}
  1070  	for _, childBlock := range content.Blocks {
  1071  		if childBlock.Type != s.TypeName {
  1072  			continue
  1073  		}
  1074  
  1075  		if u, ok := childBlock.Body.(UnknownBody); ok {
  1076  			if u.Unknown() {
  1077  				// If any block Body is unknown, then the entire block value
  1078  				// must be unknown
  1079  				return cty.UnknownVal(s.impliedType().WithoutOptionalAttributesDeep()), diags
  1080  			}
  1081  		}
  1082  
  1083  		childLabels := labelsForBlock(childBlock)
  1084  		val, _, childDiags := decode(childBlock.Body, childLabels[len(s.LabelNames):], ctx, s.Nested, false)
  1085  		targetMap := elems
  1086  		for _, key := range childBlock.Labels[:len(s.LabelNames)-1] {
  1087  			if _, exists := targetMap[key]; !exists {
  1088  				targetMap[key] = make(map[string]interface{})
  1089  			}
  1090  			targetMap = targetMap[key].(map[string]interface{})
  1091  		}
  1092  
  1093  		diags = append(diags, childDiags...)
  1094  
  1095  		key := childBlock.Labels[len(s.LabelNames)-1]
  1096  		if _, exists := targetMap[key]; exists {
  1097  			labelsBuf := bytes.Buffer{}
  1098  			for _, label := range childBlock.Labels {
  1099  				fmt.Fprintf(&labelsBuf, " %q", label)
  1100  			}
  1101  			diags = append(diags, &hcl.Diagnostic{
  1102  				Severity: hcl.DiagError,
  1103  				Summary:  fmt.Sprintf("Duplicate %s block", s.TypeName),
  1104  				Detail: fmt.Sprintf(
  1105  					"A block for %s%s was already defined. The %s labels must be unique.",
  1106  					s.TypeName, labelsBuf.String(), s.TypeName,
  1107  				),
  1108  				Subject: &childBlock.DefRange,
  1109  			})
  1110  			continue
  1111  		}
  1112  
  1113  		targetMap[key] = val
  1114  	}
  1115  
  1116  	if len(elems) == 0 {
  1117  		return cty.EmptyObjectVal, diags
  1118  	}
  1119  
  1120  	var ctyObj func(map[string]interface{}, int) cty.Value
  1121  	ctyObj = func(raw map[string]interface{}, depth int) cty.Value {
  1122  		vals := make(map[string]cty.Value, len(raw))
  1123  		if depth == 1 {
  1124  			for k, v := range raw {
  1125  				vals[k] = v.(cty.Value)
  1126  			}
  1127  		} else {
  1128  			for k, v := range raw {
  1129  				vals[k] = ctyObj(v.(map[string]interface{}), depth-1)
  1130  			}
  1131  		}
  1132  		return cty.ObjectVal(vals)
  1133  	}
  1134  
  1135  	return ctyObj(elems, len(s.LabelNames)), diags
  1136  }
  1137  
  1138  func (s *BlockObjectSpec) impliedType() cty.Type {
  1139  	// We can't predict our type, since we don't know how many blocks are
  1140  	// present and what labels they have until we decode.
  1141  	return cty.DynamicPseudoType
  1142  }
  1143  
  1144  func (s *BlockObjectSpec) sourceRange(content *hcl.BodyContent, blockLabels []blockLabel) hcl.Range {
  1145  	// We return the source range of the _first_ block of the given type,
  1146  	// since they are not guaranteed to form a contiguous range.
  1147  
  1148  	var childBlock *hcl.Block
  1149  	for _, candidate := range content.Blocks {
  1150  		if candidate.Type != s.TypeName {
  1151  			continue
  1152  		}
  1153  
  1154  		childBlock = candidate
  1155  		break
  1156  	}
  1157  
  1158  	if childBlock == nil {
  1159  		return content.MissingItemRange
  1160  	}
  1161  
  1162  	return sourceRange(childBlock.Body, labelsForBlock(childBlock), s.Nested)
  1163  }
  1164  
  1165  // A BlockAttrsSpec is a Spec that interprets a single block as if it were
  1166  // a map of some element type. That is, each attribute within the block
  1167  // becomes a key in the resulting map and the attribute's value becomes the
  1168  // element value, after conversion to the given element type. The resulting
  1169  // value is a cty.Map of the given element type.
  1170  //
  1171  // This spec imposes a validation constraint that there be exactly one block
  1172  // of the given type name and that this block may contain only attributes. The
  1173  // block does not accept any labels.
  1174  //
  1175  // This is an alternative to an AttrSpec of a map type for situations where
  1176  // block syntax is desired. Note that block syntax does not permit dynamic
  1177  // keys, construction of the result via a "for" expression, etc. In most cases
  1178  // an AttrSpec is preferred if the desired result is a map whose keys are
  1179  // chosen by the user rather than by schema.
  1180  type BlockAttrsSpec struct {
  1181  	TypeName    string
  1182  	ElementType cty.Type
  1183  	Required    bool
  1184  }
  1185  
  1186  func (s *BlockAttrsSpec) visitSameBodyChildren(cb visitFunc) {
  1187  	// leaf node
  1188  }
  1189  
  1190  // blockSpec implementation
  1191  func (s *BlockAttrsSpec) blockHeaderSchemata() []hcl.BlockHeaderSchema {
  1192  	return []hcl.BlockHeaderSchema{
  1193  		{
  1194  			Type:       s.TypeName,
  1195  			LabelNames: nil,
  1196  		},
  1197  	}
  1198  }
  1199  
  1200  // blockSpec implementation
  1201  func (s *BlockAttrsSpec) nestedSpec() Spec {
  1202  	// This is an odd case: we aren't actually going to apply a nested spec
  1203  	// in this case, since we're going to interpret the body directly as
  1204  	// attributes, but we need to return something non-nil so that the
  1205  	// decoder will recognize this as a block spec. We won't actually be
  1206  	// using this for anything at decode time.
  1207  	return noopSpec{}
  1208  }
  1209  
  1210  // specNeedingVariables implementation
  1211  func (s *BlockAttrsSpec) variablesNeeded(content *hcl.BodyContent) []hcl.Traversal {
  1212  
  1213  	block, _ := s.findBlock(content)
  1214  	if block == nil {
  1215  		return nil
  1216  	}
  1217  
  1218  	var vars []hcl.Traversal
  1219  
  1220  	attrs, diags := block.Body.JustAttributes()
  1221  	if diags.HasErrors() {
  1222  		return nil
  1223  	}
  1224  
  1225  	for _, attr := range attrs {
  1226  		vars = append(vars, attr.Expr.Variables()...)
  1227  	}
  1228  
  1229  	// We'll return the variables references in source order so that any
  1230  	// error messages that result are also in source order.
  1231  	sort.Slice(vars, func(i, j int) bool {
  1232  		return vars[i].SourceRange().Start.Byte < vars[j].SourceRange().Start.Byte
  1233  	})
  1234  
  1235  	return vars
  1236  }
  1237  
  1238  func (s *BlockAttrsSpec) decode(content *hcl.BodyContent, blockLabels []blockLabel, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
  1239  	var diags hcl.Diagnostics
  1240  
  1241  	block, other := s.findBlock(content)
  1242  	if block == nil {
  1243  		if s.Required {
  1244  			diags = append(diags, &hcl.Diagnostic{
  1245  				Severity: hcl.DiagError,
  1246  				Summary:  fmt.Sprintf("Missing %s block", s.TypeName),
  1247  				Detail: fmt.Sprintf(
  1248  					"A block of type %q is required here.", s.TypeName,
  1249  				),
  1250  				Subject: &content.MissingItemRange,
  1251  			})
  1252  		}
  1253  		return cty.NullVal(cty.Map(s.ElementType).WithoutOptionalAttributesDeep()), diags
  1254  	}
  1255  	if other != nil {
  1256  		diags = append(diags, &hcl.Diagnostic{
  1257  			Severity: hcl.DiagError,
  1258  			Summary:  fmt.Sprintf("Duplicate %s block", s.TypeName),
  1259  			Detail: fmt.Sprintf(
  1260  				"Only one block of type %q is allowed. Previous definition was at %s.",
  1261  				s.TypeName, block.DefRange.String(),
  1262  			),
  1263  			Subject: &other.DefRange,
  1264  		})
  1265  	}
  1266  
  1267  	attrs, attrDiags := block.Body.JustAttributes()
  1268  	diags = append(diags, attrDiags...)
  1269  
  1270  	if len(attrs) == 0 {
  1271  		return cty.MapValEmpty(s.ElementType), diags
  1272  	}
  1273  
  1274  	vals := make(map[string]cty.Value, len(attrs))
  1275  	for name, attr := range attrs {
  1276  		if decodeFn := customdecode.CustomExpressionDecoderForType(s.ElementType); decodeFn != nil {
  1277  			attrVal, attrDiags := decodeFn(attr.Expr, ctx)
  1278  			diags = append(diags, attrDiags...)
  1279  			if attrVal == cty.NilVal {
  1280  				attrVal = cty.UnknownVal(s.ElementType)
  1281  			}
  1282  			vals[name] = attrVal
  1283  			continue
  1284  		}
  1285  
  1286  		attrVal, attrDiags := attr.Expr.Value(ctx)
  1287  		diags = append(diags, attrDiags...)
  1288  
  1289  		attrVal, err := convert.Convert(attrVal, s.ElementType)
  1290  		if err != nil {
  1291  			diags = append(diags, &hcl.Diagnostic{
  1292  				Severity:    hcl.DiagError,
  1293  				Summary:     "Invalid attribute value",
  1294  				Detail:      fmt.Sprintf("Invalid value for attribute of %q block: %s.", s.TypeName, err),
  1295  				Subject:     attr.Expr.Range().Ptr(),
  1296  				Context:     hcl.RangeBetween(attr.NameRange, attr.Expr.Range()).Ptr(),
  1297  				Expression:  attr.Expr,
  1298  				EvalContext: ctx,
  1299  			})
  1300  			attrVal = cty.UnknownVal(s.ElementType)
  1301  		}
  1302  
  1303  		vals[name] = attrVal
  1304  	}
  1305  
  1306  	return cty.MapVal(vals), diags
  1307  }
  1308  
  1309  func (s *BlockAttrsSpec) impliedType() cty.Type {
  1310  	return cty.Map(s.ElementType)
  1311  }
  1312  
  1313  func (s *BlockAttrsSpec) sourceRange(content *hcl.BodyContent, blockLabels []blockLabel) hcl.Range {
  1314  	block, _ := s.findBlock(content)
  1315  	if block == nil {
  1316  		return content.MissingItemRange
  1317  	}
  1318  	return block.DefRange
  1319  }
  1320  
  1321  func (s *BlockAttrsSpec) findBlock(content *hcl.BodyContent) (block *hcl.Block, other *hcl.Block) {
  1322  	for _, candidate := range content.Blocks {
  1323  		if candidate.Type != s.TypeName {
  1324  			continue
  1325  		}
  1326  		if block != nil {
  1327  			return block, candidate
  1328  		}
  1329  		block = candidate
  1330  	}
  1331  
  1332  	return block, nil
  1333  }
  1334  
  1335  // A BlockLabelSpec is a Spec that returns a cty.String representing the
  1336  // label of the block its given body belongs to, if indeed its given body
  1337  // belongs to a block. It is a programming error to use this in a non-block
  1338  // context, so this spec will panic in that case.
  1339  //
  1340  // This spec only works in the nested spec within a BlockSpec, BlockListSpec,
  1341  // BlockSetSpec or BlockMapSpec.
  1342  //
  1343  // The full set of label specs used against a particular block must have a
  1344  // consecutive set of indices starting at zero. The maximum index found
  1345  // defines how many labels the corresponding blocks must have in cty source.
  1346  type BlockLabelSpec struct {
  1347  	Index int
  1348  	Name  string
  1349  }
  1350  
  1351  func (s *BlockLabelSpec) visitSameBodyChildren(cb visitFunc) {
  1352  	// leaf node
  1353  }
  1354  
  1355  func (s *BlockLabelSpec) decode(content *hcl.BodyContent, blockLabels []blockLabel, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
  1356  	if s.Index >= len(blockLabels) {
  1357  		panic("BlockListSpec used in non-block context")
  1358  	}
  1359  
  1360  	return cty.StringVal(blockLabels[s.Index].Value), nil
  1361  }
  1362  
  1363  func (s *BlockLabelSpec) impliedType() cty.Type {
  1364  	return cty.String // labels are always strings
  1365  }
  1366  
  1367  func (s *BlockLabelSpec) sourceRange(content *hcl.BodyContent, blockLabels []blockLabel) hcl.Range {
  1368  	if s.Index >= len(blockLabels) {
  1369  		panic("BlockListSpec used in non-block context")
  1370  	}
  1371  
  1372  	return blockLabels[s.Index].Range
  1373  }
  1374  
  1375  func findLabelSpecs(spec Spec) []string {
  1376  	maxIdx := -1
  1377  	var names map[int]string
  1378  
  1379  	var visit visitFunc
  1380  	visit = func(s Spec) {
  1381  		if ls, ok := s.(*BlockLabelSpec); ok {
  1382  			if maxIdx < ls.Index {
  1383  				maxIdx = ls.Index
  1384  			}
  1385  			if names == nil {
  1386  				names = make(map[int]string)
  1387  			}
  1388  			names[ls.Index] = ls.Name
  1389  		}
  1390  		s.visitSameBodyChildren(visit)
  1391  	}
  1392  
  1393  	visit(spec)
  1394  
  1395  	if maxIdx < 0 {
  1396  		return nil // no labels at all
  1397  	}
  1398  
  1399  	ret := make([]string, maxIdx+1)
  1400  	for i := range ret {
  1401  		name := names[i]
  1402  		if name == "" {
  1403  			// Should never happen if the spec is conformant, since we require
  1404  			// consecutive indices starting at zero.
  1405  			name = fmt.Sprintf("missing%02d", i)
  1406  		}
  1407  		ret[i] = name
  1408  	}
  1409  
  1410  	return ret
  1411  }
  1412  
  1413  // DefaultSpec is a spec that wraps two specs, evaluating the primary first
  1414  // and then evaluating the default if the primary returns a null value.
  1415  //
  1416  // The two specifications must have the same implied result type for correct
  1417  // operation. If not, the result is undefined.
  1418  //
  1419  // Any requirements imposed by the "Default" spec apply even if "Primary" does
  1420  // not return null. For example, if the "Default" spec is for a required
  1421  // attribute then that attribute is always required, regardless of the result
  1422  // of the "Primary" spec.
  1423  //
  1424  // The "Default" spec must not describe a nested block, since otherwise the
  1425  // result of ChildBlockTypes would not be decidable without evaluation. If
  1426  // the default spec _does_ describe a nested block then the result is
  1427  // undefined.
  1428  type DefaultSpec struct {
  1429  	Primary Spec
  1430  	Default Spec
  1431  }
  1432  
  1433  func (s *DefaultSpec) visitSameBodyChildren(cb visitFunc) {
  1434  	cb(s.Primary)
  1435  	cb(s.Default)
  1436  }
  1437  
  1438  func (s *DefaultSpec) decode(content *hcl.BodyContent, blockLabels []blockLabel, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
  1439  	val, diags := s.Primary.decode(content, blockLabels, ctx)
  1440  	if val.IsNull() {
  1441  		var moreDiags hcl.Diagnostics
  1442  		val, moreDiags = s.Default.decode(content, blockLabels, ctx)
  1443  		diags = append(diags, moreDiags...)
  1444  	}
  1445  	return val, diags
  1446  }
  1447  
  1448  func (s *DefaultSpec) impliedType() cty.Type {
  1449  	return s.Primary.impliedType()
  1450  }
  1451  
  1452  // attrSpec implementation
  1453  func (s *DefaultSpec) attrSchemata() []hcl.AttributeSchema {
  1454  	// We must pass through the union of both of our nested specs so that
  1455  	// we'll have both values available in the result.
  1456  	var ret []hcl.AttributeSchema
  1457  	if as, ok := s.Primary.(attrSpec); ok {
  1458  		ret = append(ret, as.attrSchemata()...)
  1459  	}
  1460  	if as, ok := s.Default.(attrSpec); ok {
  1461  		ret = append(ret, as.attrSchemata()...)
  1462  	}
  1463  	return ret
  1464  }
  1465  
  1466  // blockSpec implementation
  1467  func (s *DefaultSpec) blockHeaderSchemata() []hcl.BlockHeaderSchema {
  1468  	// Only the primary spec may describe a block, since otherwise
  1469  	// our nestedSpec method below can't know which to return.
  1470  	if bs, ok := s.Primary.(blockSpec); ok {
  1471  		return bs.blockHeaderSchemata()
  1472  	}
  1473  	return nil
  1474  }
  1475  
  1476  // blockSpec implementation
  1477  func (s *DefaultSpec) nestedSpec() Spec {
  1478  	if bs, ok := s.Primary.(blockSpec); ok {
  1479  		return bs.nestedSpec()
  1480  	}
  1481  	return nil
  1482  }
  1483  
  1484  func (s *DefaultSpec) sourceRange(content *hcl.BodyContent, blockLabels []blockLabel) hcl.Range {
  1485  	// We can't tell from here which of the two specs will ultimately be used
  1486  	// in our result, so we'll just assume the first. This is usually the right
  1487  	// choice because the default is often a literal spec that doesn't have a
  1488  	// reasonable source range to return anyway.
  1489  	return s.Primary.sourceRange(content, blockLabels)
  1490  }
  1491  
  1492  // TransformExprSpec is a spec that wraps another and then evaluates a given
  1493  // hcl.Expression on the result.
  1494  //
  1495  // The implied type of this spec is determined by evaluating the expression
  1496  // with an unknown value of the nested spec's implied type, which may cause
  1497  // the result to be imprecise. This spec should not be used in situations where
  1498  // precise result type information is needed.
  1499  type TransformExprSpec struct {
  1500  	Wrapped      Spec
  1501  	Expr         hcl.Expression
  1502  	TransformCtx *hcl.EvalContext
  1503  	VarName      string
  1504  }
  1505  
  1506  func (s *TransformExprSpec) visitSameBodyChildren(cb visitFunc) {
  1507  	cb(s.Wrapped)
  1508  }
  1509  
  1510  func (s *TransformExprSpec) decode(content *hcl.BodyContent, blockLabels []blockLabel, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
  1511  	wrappedVal, diags := s.Wrapped.decode(content, blockLabels, ctx)
  1512  	if diags.HasErrors() {
  1513  		// We won't try to run our function in this case, because it'll probably
  1514  		// generate confusing additional errors that will distract from the
  1515  		// root cause.
  1516  		return cty.UnknownVal(s.impliedType().WithoutOptionalAttributesDeep()), diags
  1517  	}
  1518  
  1519  	chiCtx := s.TransformCtx.NewChild()
  1520  	chiCtx.Variables = map[string]cty.Value{
  1521  		s.VarName: wrappedVal,
  1522  	}
  1523  	resultVal, resultDiags := s.Expr.Value(chiCtx)
  1524  	diags = append(diags, resultDiags...)
  1525  	return resultVal, diags
  1526  }
  1527  
  1528  func (s *TransformExprSpec) impliedType() cty.Type {
  1529  	wrappedTy := s.Wrapped.impliedType()
  1530  	chiCtx := s.TransformCtx.NewChild()
  1531  	chiCtx.Variables = map[string]cty.Value{
  1532  		s.VarName: cty.UnknownVal(wrappedTy),
  1533  	}
  1534  	resultVal, _ := s.Expr.Value(chiCtx)
  1535  	return resultVal.Type()
  1536  }
  1537  
  1538  func (s *TransformExprSpec) sourceRange(content *hcl.BodyContent, blockLabels []blockLabel) hcl.Range {
  1539  	// We'll just pass through our wrapped range here, even though that's
  1540  	// not super-accurate, because there's nothing better to return.
  1541  	return s.Wrapped.sourceRange(content, blockLabels)
  1542  }
  1543  
  1544  // TransformFuncSpec is a spec that wraps another and then evaluates a given
  1545  // cty function with the result. The given function must expect exactly one
  1546  // argument, where the result of the wrapped spec will be passed.
  1547  //
  1548  // The implied type of this spec is determined by type-checking the function
  1549  // with an unknown value of the nested spec's implied type, which may cause
  1550  // the result to be imprecise. This spec should not be used in situations where
  1551  // precise result type information is needed.
  1552  //
  1553  // If the given function produces an error when run, this spec will produce
  1554  // a non-user-actionable diagnostic message. It's the caller's responsibility
  1555  // to ensure that the given function cannot fail for any non-error result
  1556  // of the wrapped spec.
  1557  type TransformFuncSpec struct {
  1558  	Wrapped Spec
  1559  	Func    function.Function
  1560  }
  1561  
  1562  func (s *TransformFuncSpec) visitSameBodyChildren(cb visitFunc) {
  1563  	cb(s.Wrapped)
  1564  }
  1565  
  1566  func (s *TransformFuncSpec) decode(content *hcl.BodyContent, blockLabels []blockLabel, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
  1567  	wrappedVal, diags := s.Wrapped.decode(content, blockLabels, ctx)
  1568  	if diags.HasErrors() {
  1569  		// We won't try to run our function in this case, because it'll probably
  1570  		// generate confusing additional errors that will distract from the
  1571  		// root cause.
  1572  		return cty.UnknownVal(s.impliedType().WithoutOptionalAttributesDeep()), diags
  1573  	}
  1574  
  1575  	resultVal, err := s.Func.Call([]cty.Value{wrappedVal})
  1576  	if err != nil {
  1577  		// This is not a good example of a diagnostic because it is reporting
  1578  		// a programming error in the calling application, rather than something
  1579  		// an end-user could act on.
  1580  		diags = append(diags, &hcl.Diagnostic{
  1581  			Severity: hcl.DiagError,
  1582  			Summary:  "Transform function failed",
  1583  			Detail:   fmt.Sprintf("Decoder transform returned an error: %s", err),
  1584  			Subject:  s.sourceRange(content, blockLabels).Ptr(),
  1585  		})
  1586  		return cty.UnknownVal(s.impliedType().WithoutOptionalAttributesDeep()), diags
  1587  	}
  1588  
  1589  	return resultVal, diags
  1590  }
  1591  
  1592  func (s *TransformFuncSpec) impliedType() cty.Type {
  1593  	wrappedTy := s.Wrapped.impliedType()
  1594  	resultTy, err := s.Func.ReturnType([]cty.Type{wrappedTy})
  1595  	if err != nil {
  1596  		// Should never happen with a correctly-configured spec
  1597  		return cty.DynamicPseudoType
  1598  	}
  1599  
  1600  	return resultTy
  1601  }
  1602  
  1603  func (s *TransformFuncSpec) sourceRange(content *hcl.BodyContent, blockLabels []blockLabel) hcl.Range {
  1604  	// We'll just pass through our wrapped range here, even though that's
  1605  	// not super-accurate, because there's nothing better to return.
  1606  	return s.Wrapped.sourceRange(content, blockLabels)
  1607  }
  1608  
  1609  // RefineValueSpec is a spec that wraps another and applies a fixed set of [cty]
  1610  // value refinements to whatever value it produces.
  1611  //
  1612  // Refinements serve to constrain the range of any unknown values, and act as
  1613  // assertions for known values by panicking if the final value does not meet
  1614  // the refinement. Therefore applications using this spec must guarantee that
  1615  // any value passing through the RefineValueSpec will always be consistent with
  1616  // the refinements; if not then that is a bug in the application.
  1617  //
  1618  // The wrapped spec should typically be a [ValidateSpec], a [TransformFuncSpec],
  1619  // or some other adapter that guarantees that the inner result cannot possibly
  1620  // violate the refinements.
  1621  type RefineValueSpec struct {
  1622  	Wrapped Spec
  1623  
  1624  	// Refine is a function which accepts a builder for a refinement in
  1625  	// progress and uses the builder pattern to add extra refinements to it,
  1626  	// finally returning the same builder with those modifications applied.
  1627  	Refine func(*cty.RefinementBuilder) *cty.RefinementBuilder
  1628  }
  1629  
  1630  func (s *RefineValueSpec) visitSameBodyChildren(cb visitFunc) {
  1631  	cb(s.Wrapped)
  1632  }
  1633  
  1634  func (s *RefineValueSpec) decode(content *hcl.BodyContent, blockLabels []blockLabel, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
  1635  	wrappedVal, diags := s.Wrapped.decode(content, blockLabels, ctx)
  1636  	if diags.HasErrors() {
  1637  		// We won't try to run our function in this case, because it'll probably
  1638  		// generate confusing additional errors that will distract from the
  1639  		// root cause.
  1640  		return cty.UnknownVal(s.impliedType().WithoutOptionalAttributesDeep()), diags
  1641  	}
  1642  
  1643  	return wrappedVal.RefineWith(s.Refine), diags
  1644  }
  1645  
  1646  func (s *RefineValueSpec) impliedType() cty.Type {
  1647  	return s.Wrapped.impliedType()
  1648  }
  1649  
  1650  func (s *RefineValueSpec) sourceRange(content *hcl.BodyContent, blockLabels []blockLabel) hcl.Range {
  1651  	return s.Wrapped.sourceRange(content, blockLabels)
  1652  }
  1653  
  1654  // ValidateSpec is a spec that allows for extended
  1655  // developer-defined validation. The validation function receives the
  1656  // result of the wrapped spec.
  1657  //
  1658  // The Subject field of the returned Diagnostic is optional. If not
  1659  // specified, it is automatically populated with the range covered by
  1660  // the wrapped spec.
  1661  type ValidateSpec struct {
  1662  	Wrapped Spec
  1663  	Func    func(value cty.Value) hcl.Diagnostics
  1664  }
  1665  
  1666  func (s *ValidateSpec) visitSameBodyChildren(cb visitFunc) {
  1667  	cb(s.Wrapped)
  1668  }
  1669  
  1670  func (s *ValidateSpec) decode(content *hcl.BodyContent, blockLabels []blockLabel, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
  1671  	wrappedVal, diags := s.Wrapped.decode(content, blockLabels, ctx)
  1672  	if diags.HasErrors() {
  1673  		// We won't try to run our function in this case, because it'll probably
  1674  		// generate confusing additional errors that will distract from the
  1675  		// root cause.
  1676  		return cty.UnknownVal(s.impliedType().WithoutOptionalAttributesDeep()), diags
  1677  	}
  1678  
  1679  	validateDiags := s.Func(wrappedVal)
  1680  	// Auto-populate the Subject fields if they weren't set.
  1681  	for i := range validateDiags {
  1682  		if validateDiags[i].Subject == nil {
  1683  			validateDiags[i].Subject = s.sourceRange(content, blockLabels).Ptr()
  1684  		}
  1685  	}
  1686  
  1687  	diags = append(diags, validateDiags...)
  1688  	return wrappedVal, diags
  1689  }
  1690  
  1691  func (s *ValidateSpec) impliedType() cty.Type {
  1692  	return s.Wrapped.impliedType()
  1693  }
  1694  
  1695  func (s *ValidateSpec) sourceRange(content *hcl.BodyContent, blockLabels []blockLabel) hcl.Range {
  1696  	return s.Wrapped.sourceRange(content, blockLabels)
  1697  }
  1698  
  1699  // noopSpec is a placeholder spec that does nothing, used in situations where
  1700  // a non-nil placeholder spec is required. It is not exported because there is
  1701  // no reason to use it directly; it is always an implementation detail only.
  1702  type noopSpec struct {
  1703  }
  1704  
  1705  func (s noopSpec) decode(content *hcl.BodyContent, blockLabels []blockLabel, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
  1706  	return cty.NullVal(cty.DynamicPseudoType), nil
  1707  }
  1708  
  1709  func (s noopSpec) impliedType() cty.Type {
  1710  	return cty.DynamicPseudoType
  1711  }
  1712  
  1713  func (s noopSpec) visitSameBodyChildren(cb visitFunc) {
  1714  	// nothing to do
  1715  }
  1716  
  1717  func (s noopSpec) sourceRange(content *hcl.BodyContent, blockLabels []blockLabel) hcl.Range {
  1718  	// No useful range for a noopSpec, and nobody should be calling this anyway.
  1719  	return hcl.Range{
  1720  		Filename: "noopSpec",
  1721  	}
  1722  }