Skip to content

Commit e2f43f4

Browse files
committed
Preserve marks when traversing unknown values
When traversing an unknown value or a DynamicVal, the marks from that initial value must be preserved for HCL Index and GetAttr operations. This mirrors the behavior of GetAttr and Index when used directly the underlying cty values.
1 parent bf54697 commit e2f43f4

File tree

2 files changed

+116
-9
lines changed

2 files changed

+116
-9
lines changed

ops.go

+8-8
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func Index(collection, key cty.Value, srcRange *Range) (cty.Value, Diagnostics)
4949
ty := collection.Type()
5050
kty := key.Type()
5151
if kty == cty.DynamicPseudoType || ty == cty.DynamicPseudoType {
52-
return cty.DynamicVal, nil
52+
return cty.DynamicVal.WithSameMarks(collection), nil
5353
}
5454

5555
switch {
@@ -87,9 +87,9 @@ func Index(collection, key cty.Value, srcRange *Range) (cty.Value, Diagnostics)
8787
has, _ := collection.HasIndex(key).Unmark()
8888
if !has.IsKnown() {
8989
if ty.IsTupleType() {
90-
return cty.DynamicVal, nil
90+
return cty.DynamicVal.WithSameMarks(collection), nil
9191
} else {
92-
return cty.UnknownVal(ty.ElementType()), nil
92+
return cty.UnknownVal(ty.ElementType()).WithSameMarks(collection), nil
9393
}
9494
}
9595
if has.False() {
@@ -196,10 +196,10 @@ func Index(collection, key cty.Value, srcRange *Range) (cty.Value, Diagnostics)
196196
}
197197
}
198198
if !collection.IsKnown() {
199-
return cty.DynamicVal, nil
199+
return cty.DynamicVal.WithSameMarks(collection), nil
200200
}
201201
if !key.IsKnown() {
202-
return cty.DynamicVal, nil
202+
return cty.DynamicVal.WithSameMarks(collection), nil
203203
}
204204

205205
key, _ = key.Unmark()
@@ -291,13 +291,13 @@ func GetAttr(obj cty.Value, attrName string, srcRange *Range) (cty.Value, Diagno
291291
}
292292

293293
if !obj.IsKnown() {
294-
return cty.UnknownVal(ty.AttributeType(attrName)), nil
294+
return cty.UnknownVal(ty.AttributeType(attrName)).WithSameMarks(obj), nil
295295
}
296296

297297
return obj.GetAttr(attrName), nil
298298
case ty.IsMapType():
299299
if !obj.IsKnown() {
300-
return cty.UnknownVal(ty.ElementType()), nil
300+
return cty.UnknownVal(ty.ElementType()).WithSameMarks(obj), nil
301301
}
302302

303303
idx := cty.StringVal(attrName)
@@ -319,7 +319,7 @@ func GetAttr(obj cty.Value, attrName string, srcRange *Range) (cty.Value, Diagno
319319

320320
return obj.Index(idx), nil
321321
case ty == cty.DynamicPseudoType:
322-
return cty.DynamicVal, nil
322+
return cty.DynamicVal.WithSameMarks(obj), nil
323323
case ty.IsListType() && ty.ElementType().IsObjectType():
324324
// It seems a common mistake to try to access attributes on a whole
325325
// list of objects rather than on a specific individual element, so

ops_test.go

+108-1
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,113 @@ func TestApplyPath(t *testing.T) {
249249
cty.NilVal,
250250
`Attempt to get attribute from null value: This value is null, so it does not have any attributes.`,
251251
},
252+
253+
// Marks should be retained during index and getattr ops, even when
254+
// types and values are unknown. This reflects the same behavior when
255+
// using cty to directly call GetAttr and Index methods.
256+
{
257+
cty.DynamicVal.Mark("marked"),
258+
(cty.Path)(nil).GetAttr("foo"),
259+
cty.DynamicVal.Mark("marked"),
260+
``,
261+
},
262+
{
263+
cty.ObjectVal(map[string]cty.Value{
264+
"foo": cty.StringVal("should be marked"),
265+
}).Mark("marked"),
266+
(cty.Path)(nil).GetAttr("foo"),
267+
cty.StringVal("should be marked").Mark("marked"),
268+
``,
269+
},
270+
{
271+
cty.UnknownVal(cty.Object(map[string]cty.Type{
272+
"foo": cty.DynamicPseudoType,
273+
})).Mark("marked"),
274+
(cty.Path)(nil).GetAttr("foo"),
275+
cty.DynamicVal.Mark("marked"),
276+
``,
277+
},
278+
{
279+
cty.DynamicVal.Mark("marked"),
280+
(cty.Path)(nil).Index(cty.StringVal("foo")),
281+
cty.DynamicVal.Mark("marked"),
282+
``,
283+
},
284+
{
285+
cty.ObjectVal(map[string]cty.Value{
286+
"foo": cty.StringVal("should be marked"),
287+
}).Mark("marked"),
288+
(cty.Path)(nil).Index(cty.StringVal("foo")),
289+
cty.StringVal("should be marked").Mark("marked"),
290+
``,
291+
},
292+
{
293+
cty.UnknownVal(cty.Object(map[string]cty.Type{
294+
"foo": cty.DynamicPseudoType,
295+
})).Mark("marked"),
296+
(cty.Path)(nil).Index(cty.StringVal("foo")),
297+
cty.DynamicVal.Mark("marked"),
298+
``,
299+
},
300+
{
301+
cty.DynamicVal.Mark("marked"),
302+
(cty.Path)(nil).Index(cty.NumberIntVal(0)),
303+
cty.DynamicVal.Mark("marked"),
304+
``,
305+
},
306+
{
307+
cty.ListVal([]cty.Value{cty.StringVal("should be marked")}).Mark("marked"),
308+
(cty.Path)(nil).Index(cty.NumberIntVal(0)),
309+
cty.StringVal("should be marked").Mark("marked"),
310+
``,
311+
},
312+
{
313+
cty.UnknownVal(cty.List(cty.String)).Mark("marked"),
314+
(cty.Path)(nil).Index(cty.NumberIntVal(0)),
315+
cty.UnknownVal(cty.String).Mark("marked"),
316+
``,
317+
},
318+
319+
{
320+
cty.DynamicVal.Mark("marked"),
321+
(cty.Path)(nil).Index(cty.UnknownVal(cty.String)),
322+
cty.DynamicVal.Mark("marked"),
323+
``,
324+
},
325+
{
326+
cty.ObjectVal(map[string]cty.Value{
327+
"foo": cty.StringVal("should be marked"),
328+
}).Mark("marked"),
329+
(cty.Path)(nil).Index(cty.UnknownVal(cty.String)),
330+
cty.DynamicVal.Mark("marked"),
331+
``,
332+
},
333+
{
334+
cty.UnknownVal(cty.Object(map[string]cty.Type{
335+
"foo": cty.DynamicPseudoType,
336+
})).Mark("marked"),
337+
(cty.Path)(nil).Index(cty.UnknownVal(cty.String)),
338+
cty.DynamicVal.Mark("marked"),
339+
``,
340+
},
341+
{
342+
cty.DynamicVal.Mark("marked"),
343+
(cty.Path)(nil).Index(cty.UnknownVal(cty.Number)),
344+
cty.DynamicVal.Mark("marked"),
345+
``,
346+
},
347+
{
348+
cty.ListVal([]cty.Value{cty.StringVal("should be marked")}).Mark("marked"),
349+
(cty.Path)(nil).Index(cty.UnknownVal(cty.Number)),
350+
cty.UnknownVal(cty.String).Mark("marked"),
351+
``,
352+
},
353+
{
354+
cty.UnknownVal(cty.List(cty.String)).Mark("marked"),
355+
(cty.Path)(nil).Index(cty.UnknownVal(cty.Number)),
356+
cty.UnknownVal(cty.String).Mark("marked"),
357+
``,
358+
},
252359
}
253360

254361
for _, test := range tests {
@@ -257,7 +364,7 @@ func TestApplyPath(t *testing.T) {
257364
t.Logf("testing ApplyPath\nstart: %#v\npath: %#v", test.Start, test.Path)
258365

259366
for _, diag := range diags {
260-
t.Logf(diag.Error())
367+
t.Log(diag.Error())
261368
}
262369

263370
if test.WantErr != "" {

0 commit comments

Comments
 (0)