Merge pull request #2911 from crazy-max/update-hcl

vendor: update hcl dependencies
This commit is contained in:
Tõnis Tiigi 2025-01-13 10:30:04 -08:00 committed by GitHub
commit 45d2ec69f1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 231 additions and 86 deletions

6
go.mod
View File

@ -24,8 +24,8 @@ require (
github.com/gofrs/flock v0.12.1
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/google/uuid v1.6.0
github.com/hashicorp/go-cty-funcs v0.0.0-20230405223818-a090f58aa992
github.com/hashicorp/hcl/v2 v2.20.1
github.com/hashicorp/go-cty-funcs v0.0.0-20241120183456-c51673e0b3dd
github.com/hashicorp/hcl/v2 v2.23.0
github.com/in-toto/in-toto-golang v0.5.0
github.com/mitchellh/hashstructure/v2 v2.0.2
github.com/moby/buildkit v0.18.0
@ -44,7 +44,7 @@ require (
github.com/stretchr/testify v1.9.0
github.com/tonistiigi/fsutil v0.0.0-20241121093142-31cf1f437184
github.com/tonistiigi/go-csvvalue v0.0.0-20240710180619-ddb21b71c0b4
github.com/zclconf/go-cty v1.14.4
github.com/zclconf/go-cty v1.16.0
go.opentelemetry.io/otel v1.28.0
go.opentelemetry.io/otel/metric v1.28.0
go.opentelemetry.io/otel/sdk v1.28.0

16
go.sum
View File

@ -235,12 +235,12 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-cty-funcs v0.0.0-20230405223818-a090f58aa992 h1:fYOrSfO5C9PmFGtmRWSYGqq52SOoE2dXMtAn2Xzh1LQ=
github.com/hashicorp/go-cty-funcs v0.0.0-20230405223818-a090f58aa992/go.mod h1:Abjk0jbRkDaNCzsRhOv2iDCofYpX1eVsjozoiK63qLA=
github.com/hashicorp/go-cty-funcs v0.0.0-20241120183456-c51673e0b3dd h1:nwSMaLX+rf/ZPHTJHWO9K73be04SritSKvKuvpBvC2A=
github.com/hashicorp/go-cty-funcs v0.0.0-20241120183456-c51673e0b3dd/go.mod h1:Abjk0jbRkDaNCzsRhOv2iDCofYpX1eVsjozoiK63qLA=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/hcl/v2 v2.20.1 h1:M6hgdyz7HYt1UN9e61j+qKJBqR3orTWbI1HKBJEdxtc=
github.com/hashicorp/hcl/v2 v2.20.1/go.mod h1:TZDqQ4kNKCbh1iJp99FdPiUaVDDUPivbqxZulxDYqL4=
github.com/hashicorp/hcl/v2 v2.23.0 h1:Fphj1/gCylPxHutVSEOf2fBOh1VE4AuLV7+kbJf3qos=
github.com/hashicorp/hcl/v2 v2.23.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
@ -462,10 +462,10 @@ github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQ
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/zclconf/go-cty v1.4.0/go.mod h1:nHzOclRkoj++EU9ZjSrZvRG0BXIWt8c7loYc0qXAFGQ=
github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8=
github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b h1:FosyBZYxY34Wul7O/MSKey3txpPYyCqVO5ZyceuQJEI=
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8=
github.com/zclconf/go-cty v1.16.0 h1:xPKEhst+BW5D0wxebMZkxgapvOE/dw7bFTlgSc9nD6w=
github.com/zclconf/go-cty v1.16.0/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo=
github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE=

View File

@ -1,5 +1,22 @@
# HCL Changelog
## v2.22.0 (August 26, 2024)
### Enhancements
* feat: return an ExprSyntaxError for invalid references that end in a dot ([#692](https://github.com/hashicorp/hcl/pull/692))
## v2.21.0 (June 19, 2024)
### Enhancements
* Introduce `ParseTraversalPartial`, which allows traversals that include the splat (`[*]`) index operator. ([#673](https://github.com/hashicorp/hcl/pull/673))
* ext/dynblock: Now accepts marked values in `for_each`, and will transfer those marks (as much as technically possible) to values in the generated blocks. ([#679](https://github.com/hashicorp/hcl/pull/679))
### Bugs Fixed
* Expression evaluation will no longer panic if the splat operator is applied to an unknown value that has cty marks. ([#678](https://github.com/hashicorp/hcl/pull/678))
## v2.20.1 (March 26, 2024)
### Bugs Fixed

View File

@ -788,21 +788,24 @@ func (e *ConditionalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostic
})
return cty.UnknownVal(resultType), diags
}
// Now that we have all three values, collect all the marks for the result.
// Since it's possible that a condition value could be unknown, and the
// consumer needs to deal with any marks from either branch anyway, we must
// always combine them for consistent results.
condResult, condResultMarks := condResult.Unmark()
trueResult, trueResultMarks := trueResult.Unmark()
falseResult, falseResultMarks := falseResult.Unmark()
var resMarks []cty.ValueMarks
resMarks = append(resMarks, condResultMarks, trueResultMarks, falseResultMarks)
if !condResult.IsKnown() {
// we use the unmarked values throughout the unknown branch
_, condResultMarks := condResult.Unmark()
trueResult, trueResultMarks := trueResult.Unmark()
falseResult, falseResultMarks := falseResult.Unmark()
// use a value to merge marks
_, resMarks := cty.DynamicVal.WithMarks(condResultMarks, trueResultMarks, falseResultMarks).Unmark()
trueRange := trueResult.Range()
falseRange := falseResult.Range()
// if both branches are known to be null, then the result must still be null
if trueResult.IsNull() && falseResult.IsNull() {
return cty.NullVal(resultType).WithMarks(resMarks), diags
return cty.NullVal(resultType).WithMarks(resMarks...), diags
}
// We might be able to offer a refined range for the result based on
@ -841,7 +844,7 @@ func (e *ConditionalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostic
ref = ref.NumberRangeUpperBound(hi, hiInc)
}
return ref.NewValue().WithMarks(resMarks), diags
return ref.NewValue().WithMarks(resMarks...), diags
}
if trueResult.Type().IsCollectionType() && falseResult.Type().IsCollectionType() {
@ -867,7 +870,7 @@ func (e *ConditionalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostic
}
ref = ref.CollectionLengthLowerBound(lo).CollectionLengthUpperBound(hi)
return ref.NewValue().WithMarks(resMarks), diags
return ref.NewValue().WithMarks(resMarks...), diags
}
}
@ -875,7 +878,7 @@ func (e *ConditionalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostic
if trueRange.DefinitelyNotNull() && falseRange.DefinitelyNotNull() {
ret = ret.RefineNotNull()
}
return ret.WithMarks(resMarks), diags
return ret.WithMarks(resMarks...), diags
}
condResult, err := convert.Convert(condResult, cty.Bool)
@ -892,8 +895,6 @@ func (e *ConditionalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostic
return cty.UnknownVal(resultType), diags
}
// Unmark result before testing for truthiness
condResult, _ = condResult.UnmarkDeep()
if condResult.True() {
diags = append(diags, trueDiags...)
if convs[0] != nil {
@ -916,7 +917,7 @@ func (e *ConditionalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostic
trueResult = cty.UnknownVal(resultType)
}
}
return trueResult, diags
return trueResult.WithMarks(resMarks...), diags
} else {
diags = append(diags, falseDiags...)
if convs[1] != nil {
@ -939,7 +940,7 @@ func (e *ConditionalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostic
falseResult = cty.UnknownVal(resultType)
}
}
return falseResult, diags
return falseResult.WithMarks(resMarks...), diags
}
}
@ -1429,9 +1430,9 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
})
return cty.DynamicVal, diags
}
if !collVal.IsKnown() {
return cty.DynamicVal, diags
}
// Grab the CondExpr marks when we're returning early with an unknown
var condMarks cty.ValueMarks
// Before we start we'll do an early check to see if any CondExpr we've
// been given is of the wrong type. This isn't 100% reliable (it may
@ -1459,6 +1460,9 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
})
return cty.DynamicVal, diags
}
_, condMarks = result.Unmark()
_, err := convert.Convert(result, cty.Bool)
if err != nil {
diags = append(diags, &hcl.Diagnostic{
@ -1477,6 +1481,10 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
}
}
if !collVal.IsKnown() {
return cty.DynamicVal.WithMarks(append(marks, condMarks)...), diags
}
if e.KeyExpr != nil {
// Producing an object
var vals map[string]cty.Value
@ -1517,6 +1525,12 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
known = false
continue
}
// Extract and merge marks from the include expression into the
// main set of marks
_, includeMarks := includeRaw.Unmark()
marks = append(marks, includeMarks)
include, err := convert.Convert(includeRaw, cty.Bool)
if err != nil {
if known {
@ -1540,7 +1554,7 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
// Extract and merge marks from the include expression into the
// main set of marks
includeUnmarked, includeMarks := include.Unmark()
includeUnmarked, _ := include.Unmark()
marks = append(marks, includeMarks)
if includeUnmarked.False() {
// Skip this element
@ -1565,6 +1579,10 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
known = false
continue
}
_, keyMarks := keyRaw.Unmark()
marks = append(marks, keyMarks)
if !keyRaw.IsKnown() {
known = false
continue
@ -1587,8 +1605,7 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
continue
}
key, keyMarks := key.Unmark()
marks = append(marks, keyMarks)
key, _ = key.Unmark()
val, valDiags := e.ValExpr.Value(childCtx)
diags = append(diags, valDiags...)
@ -1618,7 +1635,7 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
}
if !known {
return cty.DynamicVal, diags
return cty.DynamicVal.WithMarks(marks...), diags
}
if e.Group {
@ -1664,6 +1681,12 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
known = false
continue
}
// Extract and merge marks from the include expression into the
// main set of marks
_, includeMarks := includeRaw.Unmark()
marks = append(marks, includeMarks)
if !includeRaw.IsKnown() {
// We will eventually return DynamicVal, but we'll continue
// iterating in case there are other diagnostics to gather
@ -1689,10 +1712,7 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
continue
}
// Extract and merge marks from the include expression into the
// main set of marks
includeUnmarked, includeMarks := include.Unmark()
marks = append(marks, includeMarks)
includeUnmarked, _ := include.Unmark()
if includeUnmarked.False() {
// Skip this element
continue
@ -1705,7 +1725,7 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
}
if !known {
return cty.DynamicVal, diags
return cty.DynamicVal.WithMarks(marks...), diags
}
return cty.TupleVal(vals).WithMarks(marks...), diags
@ -1780,7 +1800,7 @@ func (e *SplatExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
if sourceVal.IsNull() {
if autoUpgrade {
return cty.EmptyTupleVal, diags
return cty.EmptyTupleVal.WithSameMarks(sourceVal), diags
}
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
@ -1798,7 +1818,7 @@ func (e *SplatExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
// If we don't even know the _type_ of our source value yet then
// we'll need to defer all processing, since we can't decide our
// result type either.
return cty.DynamicVal, diags
return cty.DynamicVal.WithSameMarks(sourceVal), diags
}
upgradedUnknown := false
@ -1813,13 +1833,14 @@ func (e *SplatExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
// list of a single attribute, but we still need to check if that
// attribute actually exists.
if !sourceVal.IsKnown() {
sourceRng := sourceVal.Range()
unmarkedVal, _ := sourceVal.Unmark()
sourceRng := unmarkedVal.Range()
if sourceRng.CouldBeNull() {
upgradedUnknown = true
}
}
sourceVal = cty.TupleVal([]cty.Value{sourceVal})
sourceVal = cty.TupleVal([]cty.Value{sourceVal}).WithSameMarks(sourceVal)
sourceTy = sourceVal.Type()
}
@ -1900,14 +1921,14 @@ func (e *SplatExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
e.Item.clearValue(ctx) // clean up our temporary value
if upgradedUnknown {
return cty.DynamicVal, diags
return cty.DynamicVal.WithMarks(marks), diags
}
if !isKnown {
// We'll ingore the resultTy diagnostics in this case since they
// will just be the same errors we saw while iterating above.
ty, _ := resultTy()
return cty.UnknownVal(ty), diags
return cty.UnknownVal(ty).WithMarks(marks), diags
}
switch {
@ -1915,7 +1936,7 @@ func (e *SplatExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
if len(vals) == 0 {
ty, tyDiags := resultTy()
diags = append(diags, tyDiags...)
return cty.ListValEmpty(ty.ElementType()), diags
return cty.ListValEmpty(ty.ElementType()).WithMarks(marks), diags
}
return cty.ListVal(vals).WithMarks(marks), diags
default:

View File

@ -811,9 +811,16 @@ Traversal:
// will probably be misparsed until we hit something that
// allows us to re-sync.
//
// We will probably need to do something better here eventually
// in order to support autocomplete triggered by typing a
// period.
// Returning an ExprSyntaxError allows us to pass more information
// about the invalid expression to the caller, which can then
// use this for example for completions that happen after typing
// a dot in an editor.
ret = &ExprSyntaxError{
Placeholder: cty.DynamicVal,
ParseDiags: diags,
SrcRange: hcl.RangeBetween(from.Range(), dot.Range),
}
p.setRecovery()
}
@ -1516,6 +1523,16 @@ func (p *parser) parseObjectCons() (Expression, hcl.Diagnostics) {
diags = append(diags, valueDiags...)
if p.recovery && valueDiags.HasErrors() {
// If the value is an ExprSyntaxError, we can add an item with it, even though we will recover afterwards
// This allows downstream consumers to still retrieve this first invalid item, even though following items
// won't be parsed. This is useful for supplying completions.
if exprSyntaxError, ok := value.(*ExprSyntaxError); ok {
items = append(items, ObjectConsItem{
KeyExpr: key,
ValueExpr: exprSyntaxError,
})
}
// If expression parsing failed then we are probably in a strange
// place in the token stream, so we'll bail out and try to reset
// to after our closing brace to allow parsing to continue.

View File

@ -4,8 +4,9 @@
package hclsyntax
import (
"github.com/hashicorp/hcl/v2"
"github.com/zclconf/go-cty/cty"
"github.com/hashicorp/hcl/v2"
)
// ParseTraversalAbs parses an absolute traversal that is assumed to consume
@ -13,6 +14,26 @@ import (
// behavior is not supported here because traversals are not expected to
// be parsed as part of a larger program.
func (p *parser) ParseTraversalAbs() (hcl.Traversal, hcl.Diagnostics) {
return p.parseTraversal(false)
}
// ParseTraversalPartial parses an absolute traversal that is permitted
// to contain splat ([*]) expressions. Only splat expressions within square
// brackets are permitted ([*]); splat expressions within attribute names are
// not permitted (.*).
//
// The meaning of partial here is that the traversal may be incomplete, in that
// any splat expression indicates reference to a potentially unknown number of
// elements.
//
// Traversals that include splats cannot be automatically traversed by HCL using
// the TraversalAbs or TraversalRel methods. Instead, the caller must handle
// the traversals manually.
func (p *parser) ParseTraversalPartial() (hcl.Traversal, hcl.Diagnostics) {
return p.parseTraversal(true)
}
func (p *parser) parseTraversal(allowSplats bool) (hcl.Traversal, hcl.Diagnostics) {
var ret hcl.Traversal
var diags hcl.Diagnostics
@ -127,6 +148,34 @@ func (p *parser) ParseTraversalAbs() (hcl.Traversal, hcl.Diagnostics) {
return ret, diags
}
case TokenStar:
if allowSplats {
p.Read() // Eat the star.
close := p.Read()
if close.Type != TokenCBrack {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Unclosed index brackets",
Detail: "Index key must be followed by a closing bracket.",
Subject: &close.Range,
Context: hcl.RangeBetween(open.Range, close.Range).Ptr(),
})
}
ret = append(ret, hcl.TraverseSplat{
SrcRange: hcl.RangeBetween(open.Range, close.Range),
})
if diags.HasErrors() {
return ret, diags
}
continue
}
// Otherwise, return the error below for the star.
fallthrough
default:
if next.Type == TokenStar {
diags = append(diags, &hcl.Diagnostic{

View File

@ -118,6 +118,37 @@ func ParseTraversalAbs(src []byte, filename string, start hcl.Pos) (hcl.Traversa
return expr, diags
}
// ParseTraversalPartial matches the behavior of ParseTraversalAbs except
// that it allows splat expressions ([*]) to appear in the traversal.
//
// The returned traversals are "partial" in that the splat expression indicates
// an unknown value for the index.
//
// Traversals that include splats cannot be automatically traversed by HCL using
// the TraversalAbs or TraversalRel methods. Instead, the caller must handle
// the traversals manually.
func ParseTraversalPartial(src []byte, filename string, start hcl.Pos) (hcl.Traversal, hcl.Diagnostics) {
tokens, diags := LexExpression(src, filename, start)
peeker := newPeeker(tokens, false)
parser := &parser{peeker: peeker}
// Bare traverals are always parsed in "ignore newlines" mode, as if
// they were wrapped in parentheses.
parser.PushIncludeNewlines(false)
expr, parseDiags := parser.ParseTraversalPartial()
diags = append(diags, parseDiags...)
parser.PopIncludeNewlines()
// Panic if the parser uses incorrect stack discipline with the peeker's
// newlines stack, since otherwise it will produce confusing downstream
// errors.
peeker.AssertEmptyIncludeNewlinesStack()
return expr, diags
}
// LexConfig performs lexical analysis on the given buffer, treating it as a
// whole HCL config file, and returns the resulting tokens.
//

View File

@ -49,7 +49,7 @@ func Index(collection, key cty.Value, srcRange *Range) (cty.Value, Diagnostics)
ty := collection.Type()
kty := key.Type()
if kty == cty.DynamicPseudoType || ty == cty.DynamicPseudoType {
return cty.DynamicVal, nil
return cty.DynamicVal.WithSameMarks(collection), nil
}
switch {
@ -87,9 +87,9 @@ func Index(collection, key cty.Value, srcRange *Range) (cty.Value, Diagnostics)
has, _ := collection.HasIndex(key).Unmark()
if !has.IsKnown() {
if ty.IsTupleType() {
return cty.DynamicVal, nil
return cty.DynamicVal.WithSameMarks(collection), nil
} else {
return cty.UnknownVal(ty.ElementType()), nil
return cty.UnknownVal(ty.ElementType()).WithSameMarks(collection), nil
}
}
if has.False() {
@ -196,10 +196,10 @@ func Index(collection, key cty.Value, srcRange *Range) (cty.Value, Diagnostics)
}
}
if !collection.IsKnown() {
return cty.DynamicVal, nil
return cty.DynamicVal.WithSameMarks(collection), nil
}
if !key.IsKnown() {
return cty.DynamicVal, nil
return cty.DynamicVal.WithSameMarks(collection), nil
}
key, _ = key.Unmark()
@ -291,13 +291,13 @@ func GetAttr(obj cty.Value, attrName string, srcRange *Range) (cty.Value, Diagno
}
if !obj.IsKnown() {
return cty.UnknownVal(ty.AttributeType(attrName)), nil
return cty.UnknownVal(ty.AttributeType(attrName)).WithSameMarks(obj), nil
}
return obj.GetAttr(attrName), nil
case ty.IsMapType():
if !obj.IsKnown() {
return cty.UnknownVal(ty.ElementType()), nil
return cty.UnknownVal(ty.ElementType()).WithSameMarks(obj), nil
}
idx := cty.StringVal(attrName)
@ -319,7 +319,7 @@ func GetAttr(obj cty.Value, attrName string, srcRange *Range) (cty.Value, Diagno
return obj.Index(idx), nil
case ty == cty.DynamicPseudoType:
return cty.DynamicVal, nil
return cty.DynamicVal.WithSameMarks(obj), nil
case ty.IsListType() && ty.ElementType().IsObjectType():
// It seems a common mistake to try to access attributes on a whole
// list of objects rather than on a specific individual element, so

View File

@ -96,7 +96,7 @@ of the implementation language.
### _Dynamic Attributes_ Processing
The _schema-driven_ processing model is useful when the expected structure
of a body is known a priori by the calling application. Some blocks are
of a body is known by the calling application. Some blocks are
instead more free-form, such as a user-provided set of arbitrary key/value
pairs.

View File

@ -171,12 +171,16 @@ func getConversionKnown(in cty.Type, out cty.Type, unsafe bool) conversion {
}
if out.IsCapsuleType() {
if fn := out.CapsuleOps().ConversionTo; fn != nil {
return conversionToCapsule(in, out, fn)
if conv := conversionToCapsule(in, out, fn); conv != nil {
return conv
}
}
}
if in.IsCapsuleType() {
if fn := in.CapsuleOps().ConversionFrom; fn != nil {
return conversionFromCapsule(in, out, fn)
if conv := conversionFromCapsule(in, out, fn); conv != nil {
return conv
}
}
}
// No conversion operation is available, then.

View File

@ -162,7 +162,7 @@ func conversionCollectionToMap(ety cty.Type, conv conversion) conversion {
if ety == cty.DynamicPseudoType {
return cty.MapValEmpty(val.Type().ElementType()), nil
}
return cty.MapValEmpty(ety), nil
return cty.MapValEmpty(ety.WithoutOptionalAttributesDeep()), nil
}
if ety.IsCollectionType() || ety.IsObjectType() {

View File

@ -251,15 +251,25 @@ func (f Function) Call(args []cty.Value) (val cty.Value, err error) {
if err != nil {
return cty.NilVal, err
}
var resultMarks []cty.ValueMarks
// If we are returning an unknown early due to some unknown in the
// arguments, we first need to complete the iteration over all the args
// to ensure we collect as many marks as possible for resultMarks.
returnUnknown := false
if dynTypeArgs {
// returnTypeForValues sets this if any argument was inexactly typed
// and the corresponding parameter did not indicate it could deal with
// that. In that case we also avoid calling the implementation function
// because it will also typically not be ready to deal with that case.
return cty.UnknownVal(expectedType), nil
returnUnknown = true
}
if refineResult := f.spec.RefineResult; refineResult != nil {
// If returnUnknown is set already, it means we don't have a refinement
// because of dynTypeArgs, but we may still need to collect marks from the
// rest of the arguments.
if refineResult := f.spec.RefineResult; refineResult != nil && !returnUnknown {
// If this function has a refinement callback then we'll refine
// our result value in the same way regardless of how we return.
// It's the function author's responsibility to ensure that the
@ -280,15 +290,10 @@ func (f Function) Call(args []cty.Value) (val cty.Value, err error) {
// values and marked values.
posArgs := args[:len(f.spec.Params)]
varArgs := args[len(f.spec.Params):]
var resultMarks []cty.ValueMarks
for i, spec := range f.spec.Params {
val := posArgs[i]
if !val.IsKnown() && !spec.AllowUnknown {
return cty.UnknownVal(expectedType), nil
}
if !spec.AllowMarked {
unwrappedVal, marks := val.UnmarkDeep()
if len(marks) > 0 {
@ -305,14 +310,15 @@ func (f Function) Call(args []cty.Value) (val cty.Value, err error) {
args = newArgs
}
}
if !val.IsKnown() && !spec.AllowUnknown {
returnUnknown = true
}
}
if f.spec.VarParam != nil {
spec := f.spec.VarParam
for i, val := range varArgs {
if !val.IsKnown() && !spec.AllowUnknown {
return cty.UnknownVal(expectedType), nil
}
if !spec.AllowMarked {
unwrappedVal, marks := val.UnmarkDeep()
if len(marks) > 0 {
@ -323,9 +329,16 @@ func (f Function) Call(args []cty.Value) (val cty.Value, err error) {
args = newArgs
}
}
if !val.IsKnown() && !spec.AllowUnknown {
returnUnknown = true
}
}
}
if returnUnknown {
return cty.UnknownVal(expectedType).WithMarks(resultMarks...), nil
}
var retVal cty.Value
{
// Intercept any panics from the function and return them as normal errors,

View File

@ -147,12 +147,6 @@ var ElementFunc = function.New(&function.Spec{
},
Type: func(args []cty.Value) (cty.Type, error) {
list := args[0]
index := args[1]
if index.IsKnown() {
if index.LessThan(cty.NumberIntVal(0)).True() {
return cty.DynamicPseudoType, fmt.Errorf("cannot use element function with a negative index")
}
}
listTy := list.Type()
switch {
@ -189,10 +183,6 @@ var ElementFunc = function.New(&function.Spec{
return cty.DynamicVal, fmt.Errorf("invalid index: %s", err)
}
if args[1].LessThan(cty.NumberIntVal(0)).True() {
return cty.DynamicVal, fmt.Errorf("cannot use element function with a negative index")
}
input, marks := args[0].Unmark()
if !input.IsKnown() {
return cty.UnknownVal(retType), nil
@ -203,6 +193,9 @@ var ElementFunc = function.New(&function.Spec{
return cty.DynamicVal, errors.New("cannot use element function with an empty list")
}
index = index % l
if index < 0 {
index += l
}
// We did all the necessary type checks in the type function above,
// so this is guaranteed not to fail.

View File

@ -213,7 +213,7 @@ func transform(path Path, val Value, t Transformer) (Value, error) {
atys := ty.AttributeTypes()
newAVs := make(map[string]Value)
for name := range atys {
av := val.GetAttr(name)
av := rawVal.GetAttr(name)
path := append(path, GetAttrStep{
Name: name,
})

6
vendor/modules.txt vendored
View File

@ -414,7 +414,7 @@ github.com/hashicorp/errwrap
# github.com/hashicorp/go-cleanhttp v0.5.2
## explicit; go 1.13
github.com/hashicorp/go-cleanhttp
# github.com/hashicorp/go-cty-funcs v0.0.0-20230405223818-a090f58aa992
# github.com/hashicorp/go-cty-funcs v0.0.0-20241120183456-c51673e0b3dd
## explicit; go 1.14
github.com/hashicorp/go-cty-funcs/cidr
github.com/hashicorp/go-cty-funcs/crypto
@ -423,7 +423,7 @@ github.com/hashicorp/go-cty-funcs/uuid
# github.com/hashicorp/go-multierror v1.1.1
## explicit; go 1.13
github.com/hashicorp/go-multierror
# github.com/hashicorp/hcl/v2 v2.20.1
# github.com/hashicorp/hcl/v2 v2.23.0
## explicit; go 1.18
github.com/hashicorp/hcl/v2
github.com/hashicorp/hcl/v2/ext/customdecode
@ -738,7 +738,7 @@ github.com/xeipuuv/gojsonreference
# github.com/xeipuuv/gojsonschema v1.2.0
## explicit
github.com/xeipuuv/gojsonschema
# github.com/zclconf/go-cty v1.14.4
# github.com/zclconf/go-cty v1.16.0
## explicit; go 1.18
github.com/zclconf/go-cty/cty
github.com/zclconf/go-cty/cty/convert