Skip to content

Commit

Permalink
Check for duplicate keys in objects when building types from expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
liamcervante committed Aug 28, 2023
1 parent 527ec31 commit 4259e4b
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 2 deletions.
15 changes: 14 additions & 1 deletion ext/typeexpr/get_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ package typeexpr
import (
"fmt"

"github.com/hashicorp/hcl/v2"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/convert"

"github.com/hashicorp/hcl/v2"
)

const invalidTypeSummary = "Invalid type specification"
Expand Down Expand Up @@ -179,6 +180,18 @@ func getType(expr hcl.Expression, constraint, withDefaults bool) (cty.Type, *Def
})
continue
}

if _, exists := atys[attrName]; exists {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: invalidTypeSummary,
Detail: "Object constructor map keys must be unique.",
Subject: attrDef.Key.Range().Ptr(),
Context: expr.Range().Ptr(),
})
continue
}

atyExpr := attrDef.Value

// the attribute type expression might be wrapped in the special
Expand Down
27 changes: 26 additions & 1 deletion ext/typeexpr/get_type_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ import (
"github.com/hashicorp/hcl/v2/gohcl"

"github.com/google/go-cmp/cmp"
"github.com/zclconf/go-cty/cty"

"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/hashicorp/hcl/v2/json"
"github.com/zclconf/go-cty/cty"
)

var (
Expand Down Expand Up @@ -700,6 +701,30 @@ func TestGetTypeDefaults(t *testing.T) {
nil,
`Optional attribute modifier expects at most two arguments: the attribute type, and a default value.`,
},

// Duplicate arguments.
{
`map(object({operations=optional(list(string), []),type=optional(string, "ABC"),type=optional(number)}))`,
&Defaults{
Type: cty.Map(cty.ObjectWithOptionalAttrs(map[string]cty.Type{
"operations": cty.List(cty.String),
"type": cty.String,
}, []string{"operations", "type"})),
Children: map[string]*Defaults{
"": {
Type: cty.ObjectWithOptionalAttrs(map[string]cty.Type{
"operations": cty.List(cty.String),
"type": cty.String,
}, []string{"operations", "type"}),
DefaultValues: map[string]cty.Value{
"operations": cty.ListValEmpty(cty.String),
"type": cty.StringVal("ABC"),
},
},
},
},
"Object constructor map keys must be unique.",
},
}

for _, test := range tests {
Expand Down

0 comments on commit 4259e4b

Please sign in to comment.