Skip to content

ext/typeexpr: render optional attributes in TypeString - #815

Open
sueun-dev wants to merge 1 commit into
hashicorp:mainfrom
sueun-dev:typeexpr-typestring-optional
Open

sueun-dev wants to merge 1 commit into
hashicorp:mainfrom
sueun-dev:typeexpr-typestring-optional

Conversation

@sueun-dev

Copy link
Copy Markdown

Description

TypeString renders object types but drops the optional(...) modifier, so its output does not round-trip back through TypeConstraint.

The doc comment says the result is rendered "as it would be expected to appear in the HCL native syntax" and that it "produces reasonable results only for types like what would be produced by the Type and TypeConstraint functions." TypeConstraint does produce object types with optional attributes, but TypeString emits them as plain required attributes:

ty := cty.ObjectWithOptionalAttrs(map[string]cty.Type{"foo": cty.Bool}, []string{"foo"})
typeexpr.TypeString(ty) // "object({foo=bool})"  -- optional dropped

Re-parsing that string gives AttributeOptional("foo") == false, so an optional attribute silently becomes required.

optional(...) parsing was added in 47464b2 but TypeString was never updated to render it. This fixes that by wrapping optional attributes in optional(...). Default values are tracked in the separate Defaults struct rather than in cty.Type, so they aren't available here; optional(type) is valid native syntax and restores the round-trip.

Related Issue

None.

How Has This Been Tested?

Added two cases to TestTypeString. They fail before the change:

got:  object({foo=bool})
want: object({foo=optional(bool)})

and pass after it. go test ./ext/typeexpr/..., go vet ./ext/typeexpr/..., and gofmt -l are clean. Confirmed the corrected output re-parses: object({a=optional(string)}) yields AttributeOptional("a") == true.

Happy to add a CHANGELOG entry if you'd like one.

TypeString rendered object types but dropped the optional(...) modifier,
so its output did not round-trip through TypeConstraint: an optional
attribute silently became required when the string was re-parsed. Wrap
optional attributes in optional(...). Default values are tracked in the
separate Defaults struct rather than in cty.Type, so they aren't
available here; optional(type) is valid native syntax and restores the
round-trip.
@sueun-dev
sueun-dev requested a review from a team as a code owner July 11, 2026 07:08
@hashicorp-cla-app

Copy link
Copy Markdown

CLA assistant check

Thank you for your submission! We require that all contributors sign our Contributor License Agreement ("CLA") before we can accept the contribution. Read and sign the agreement

Learn more about why HashiCorp requires a CLA and what the CLA includes

Have you signed the CLA already but the status is still pending? Recheck it.

1 similar comment
@hashicorp-cla-app

Copy link
Copy Markdown

CLA assistant check

Thank you for your submission! We require that all contributors sign our Contributor License Agreement ("CLA") before we can accept the contribution. Read and sign the agreement

Learn more about why HashiCorp requires a CLA and what the CLA includes

Have you signed the CLA already but the status is still pending? Recheck it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant