func TypeCanBeBlocks(ty cty.Type) bool {
	return (ty.IsListType() || ty.IsSetType()) && ty.ElementType().IsObjectType()
}
TypeCanBeBlocks returns true if the given type is a list-of-object or
set-of-object type, and would thus be subject to the blocktoattr fixup
if used as an attribute type.
package blocktoattr
import (
	"github.com/hashicorp/hcl/v2"
	"github.com/hashicorp/terraform/configs/configschema"
	"github.com/zclconf/go-cty/cty"
)
func ambiguousNames(schema *configschema.Block) map[string]struct{} {
	if schema == nil {
		return nil
	}
	ambiguousNames := make(map[string]struct{})
	for name, attrS := range schema.Attributes {
		aty := attrS.Type
		if (aty.IsListType() || aty.IsSetType()) && aty.ElementType().IsObjectType() {
			ambiguousNames[name] = struct{}{}
		}
	}
	return ambiguousNames
}
func effectiveSchema(given *hcl.BodySchema, body hcl.Body, ambiguousNames map[string]struct{}, dynamicExpanded bool) *hcl.BodySchema {
	ret := &hcl.BodySchema{}
	appearsAsBlock := make(map[string]struct{})
	{
		var probeSchema hcl.BodySchema
		for name := range ambiguousNames {
			probeSchema = hcl.BodySchema{
				Attributes: []hcl.AttributeSchema{
					{
						Name: name,
					},
				},
			}
			content, _, _ := body.PartialContent(&probeSchema)
			if _, exists := content.Attributes[name]; exists {
				continue
			}
			probeSchema = hcl.BodySchema{
				Blocks: []hcl.BlockHeaderSchema{
					{
						Type: name,
					},
				},
			}
			content, _, _ = body.PartialContent(&probeSchema)
			if len(content.Blocks) > 0 || dynamicExpanded {
				appearsAsBlock[name] = struct{}{}
			}
		}
		if !dynamicExpanded {
			probeSchema = hcl.BodySchema{
				Blocks: []hcl.BlockHeaderSchema{
					{
						Type:       "dynamic",
						LabelNames: []string{"type"},
					},
				},
			}
			content, _, _ := body.PartialContent(&probeSchema)
			for _, block := range content.Blocks {
				if _, exists := ambiguousNames[block.Labels[0]]; exists {
					appearsAsBlock[block.Labels[0]] = struct{}{}
				}
			}
		}
	}
	for _, attrS := range given.Attributes {
		if _, exists := appearsAsBlock[attrS.Name]; exists {
			ret.Blocks = append(ret.Blocks, hcl.BlockHeaderSchema{
				Type: attrS.Name,
			})
		} else {
			ret.Attributes = append(ret.Attributes, attrS)
		}
	}
	ret.Blocks = append(ret.Blocks, given.Blocks...)
	return ret
}
func SchemaForCtyElementType(ty cty.Type) *configschema.Block {
	atys := ty.AttributeTypes()
	ret := &configschema.Block{
		Attributes: make(map[string]*configschema.Attribute, len(atys)),
	}
	for name, aty := range atys {
		ret.Attributes[name] = &configschema.Attribute{
			Type:     aty,
			Optional: true,
		}
	}
	return ret
}
func SchemaForCtyContainerType(ty cty.Type) *configschema.NestedBlock {
	var nesting configschema.NestingMode
	switch {
	case ty.IsListType():
		nesting = configschema.NestingList
	case ty.IsSetType():
		nesting = configschema.NestingSet
	default:
		panic("unsuitable type")
	}
	nested := SchemaForCtyElementType(ty.ElementType())
	return &configschema.NestedBlock{
		Nesting: nesting,
		Block:   *nested,
	}
}