38
38
switch {
39
39
// if both are unknown, we don't short circuit anything
40
40
case ! lhs .IsKnown () && ! rhs .IsKnown ():
41
+ // short-circuit left-to-right when encountering a good unknown
42
+ // value and both are unknown.
43
+ if ! lhsDiags .HasErrors () {
44
+ return cty .UnknownVal (cty .Bool ).RefineNotNull (), lhsDiags
45
+ }
46
+ // If the LHS has an error, the RHS might too. Don't
47
+ // short-circuit so both diags get collected.
41
48
return cty .NilVal , nil
42
49
43
50
// for ||, a single true is the controlling condition
46
53
case rhs .IsKnown () && rhs .True ():
47
54
return cty .True , rhsDiags
48
55
49
- // if the opposing side is false we can't sort -circuit based on
56
+ // if the opposing side is false we can't short -circuit based on
50
57
// boolean logic, so an unknown becomes the controlling condition
51
58
case ! lhs .IsKnown () && rhs .False ():
52
59
return cty .UnknownVal (cty .Bool ).RefineNotNull (), lhsDiags
62
69
Type : cty .Bool ,
63
70
64
71
ShortCircuit : func (lhs , rhs cty.Value , lhsDiags , rhsDiags hcl.Diagnostics ) (cty.Value , hcl.Diagnostics ) {
72
+
65
73
switch {
66
- // if both are unknown, we don't short circuit anything
67
74
case ! lhs .IsKnown () && ! rhs .IsKnown ():
75
+ // short-circuit left-to-right when encountering a good unknown
76
+ // value and both are unknown.
77
+ if ! lhsDiags .HasErrors () {
78
+ return cty .UnknownVal (cty .Bool ).RefineNotNull (), lhsDiags
79
+ }
80
+ // If the LHS has an error, the RHS might too. Don't
81
+ // short-circuit so both diags get collected.
68
82
return cty .NilVal , nil
69
83
70
84
// For &&, a single false is the controlling condition
@@ -73,14 +87,13 @@ var (
73
87
case rhs .IsKnown () && rhs .False ():
74
88
return cty .False , rhsDiags
75
89
76
- // if the opposing side is true we can't sort -circuit based on
90
+ // if the opposing side is true we can't short -circuit based on
77
91
// boolean logic, so an unknown becomes the controlling condition
78
92
case ! lhs .IsKnown () && rhs .True ():
79
93
return cty .UnknownVal (cty .Bool ).RefineNotNull (), lhsDiags
80
94
case ! rhs .IsKnown () && lhs .True ():
81
95
return cty .UnknownVal (cty .Bool ).RefineNotNull (), rhsDiags
82
96
}
83
-
84
97
return cty .NilVal , nil
85
98
},
86
99
}
@@ -242,9 +255,6 @@ func (e *BinaryOpExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics)
242
255
lhsVal , lhsMarks := lhsVal .Unmark ()
243
256
rhsVal , rhsMarks := rhsVal .Unmark ()
244
257
245
- // If we short-circuited above and still passed the type-check of RHS then
246
- // we'll halt here and return the short-circuit result rather than actually
247
- // executing the operation.
248
258
if e .Op .ShortCircuit != nil {
249
259
forceResult , diags := e .Op .ShortCircuit (lhsVal , rhsVal , lhsDiags , rhsDiags )
250
260
if forceResult != cty .NilVal {
@@ -256,6 +266,8 @@ func (e *BinaryOpExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics)
256
266
}
257
267
}
258
268
269
+ diags = append (diags , lhsDiags ... )
270
+ diags = append (diags , rhsDiags ... )
259
271
if diags .HasErrors () {
260
272
// Don't actually try the call if we have errors, since the this will
261
273
// probably just produce confusing duplicate diagnostics.
0 commit comments