Skip to content

Commit

Permalink
cty: Known result special cases for Multiply, And, and Or
Browse files Browse the repository at this point in the history
Now that we're in the business of trying to produce known values from
operations on unknown inputs where possible, these are some simple cases
that hold regardless of the range/refinements of the unknown operands and
can help take a particular unknown result out of consideration when
evaluating a broader expression.
  • Loading branch information
apparentlymart committed Feb 8, 2023
1 parent 1291057 commit 199911c
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 3 deletions.
17 changes: 17 additions & 0 deletions cty/value_ops.go
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,11 @@ func (val Value) Multiply(other Value) Value {
}

if shortCircuit := mustTypeCheck(Number, Number, val, other); shortCircuit != nil {
// If either value is exactly zero then the result must either be
// zero or an error.
if val == Zero || other == Zero {
return Zero
}
shortCircuit = forceShortCircuitType(shortCircuit, Number)
ret := shortCircuit.RefineWith(numericRangeArithmetic(Value.Multiply, val.Range(), other.Range()))
return ret.RefineNotNull()
Expand Down Expand Up @@ -1250,6 +1255,12 @@ func (val Value) And(other Value) Value {
}

if shortCircuit := mustTypeCheck(Bool, Bool, val, other); shortCircuit != nil {
// If either value is known to be exactly False then it doesn't
// matter what the other value is, because the final result must
// either be False or an error.
if val == False || other == False {
return False
}
shortCircuit = forceShortCircuitType(shortCircuit, Bool)
return (*shortCircuit).RefineNotNull()
}
Expand All @@ -1267,6 +1278,12 @@ func (val Value) Or(other Value) Value {
}

if shortCircuit := mustTypeCheck(Bool, Bool, val, other); shortCircuit != nil {
// If either value is known to be exactly True then it doesn't
// matter what the other value is, because the final result must
// either be True or an error.
if val == True || other == True {
return True
}
shortCircuit = forceShortCircuitType(shortCircuit, Bool)
return (*shortCircuit).RefineNotNull()
}
Expand Down
56 changes: 53 additions & 3 deletions cty/value_ops_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2072,12 +2072,22 @@ func TestValueMultiply(t *testing.T) {
NumberRangeLowerBound(NumberIntVal(6), true).
NewValue(),
},
{
Zero,
UnknownVal(Number),
Zero,
},
{
UnknownVal(Number),
Zero,
Zero,
},
{
Zero,
UnknownVal(Number).Refine().
NumberRangeLowerBound(NumberIntVal(2), false).
NewValue(),
UnknownVal(Number).RefineNotNull(), // We can't currently refine this case
Zero,
},
{
UnknownVal(Number).Refine().
Expand Down Expand Up @@ -3033,6 +3043,16 @@ func TestValueAnd(t *testing.T) {
True,
UnknownVal(Bool).RefineNotNull(),
},
{
False,
UnknownVal(Bool),
False,
},
{
UnknownVal(Bool),
False,
False,
},
{
DynamicVal,
DynamicVal,
Expand All @@ -3048,6 +3068,16 @@ func TestValueAnd(t *testing.T) {
True,
UnknownVal(Bool).RefineNotNull(),
},
{
False,
DynamicVal,
False,
},
{
DynamicVal,
False,
False,
},
{
True.Mark(1),
True,
Expand Down Expand Up @@ -3109,11 +3139,21 @@ func TestValueOr(t *testing.T) {
{
True,
UnknownVal(Bool),
UnknownVal(Bool).RefineNotNull(),
True,
},
{
UnknownVal(Bool),
True,
True,
},
{
False,
UnknownVal(Bool),
UnknownVal(Bool).RefineNotNull(),
},
{
UnknownVal(Bool),
False,
UnknownVal(Bool).RefineNotNull(),
},
{
Expand All @@ -3124,11 +3164,21 @@ func TestValueOr(t *testing.T) {
{
True,
DynamicVal,
UnknownVal(Bool).RefineNotNull(),
True,
},
{
DynamicVal,
True,
True,
},
{
False,
DynamicVal,
UnknownVal(Bool).RefineNotNull(),
},
{
DynamicVal,
False,
UnknownVal(Bool).RefineNotNull(),
},
{
Expand Down

0 comments on commit 199911c

Please sign in to comment.