@@ -696,64 +696,95 @@ func (e *ConditionalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostic
696
696
return cty .UnknownVal (resultType ), diags
697
697
}
698
698
if ! condResult .IsKnown () {
699
+ // we use the unmarked values throughout the unknown branch
700
+ _ , condResultMarks := condResult .Unmark ()
701
+ trueResult , trueResultMarks := trueResult .Unmark ()
702
+ falseResult , falseResultMarks := falseResult .Unmark ()
703
+
704
+ // use a value to merge marks
705
+ _ , resMarks := cty .DynamicVal .WithMarks (condResultMarks , trueResultMarks , falseResultMarks ).Unmark ()
706
+
707
+ trueRange := trueResult .Range ()
708
+ falseRange := falseResult .Range ()
709
+
710
+ // if both branches are known to be null, then the result must still be null
711
+ if trueResult .IsNull () && falseResult .IsNull () {
712
+ return cty .NullVal (resultType ).WithMarks (resMarks ), diags
713
+ }
714
+
699
715
// We might be able to offer a refined range for the result based on
700
716
// the two possible outcomes.
701
717
if trueResult .Type () == cty .Number && falseResult .Type () == cty .Number {
702
- // This case deals with the common case of (predicate ? 1 : 0) and
703
- // significantly decreases the range of the result in that case.
704
- if ! (trueResult .IsNull () || falseResult .IsNull ()) {
705
- if gt := trueResult .GreaterThan (falseResult ); gt .IsKnown () {
706
- b := cty .UnknownVal (cty .Number ).Refine ()
707
- if gt .True () {
708
- b = b .
709
- NumberRangeLowerBound (falseResult , true ).
710
- NumberRangeUpperBound (trueResult , true )
711
- } else {
712
- b = b .
713
- NumberRangeLowerBound (trueResult , true ).
714
- NumberRangeUpperBound (falseResult , true )
715
- }
716
- b = b .NotNull () // If neither of the results is null then the result can't be either
717
- return b .NewValue ().WithSameMarks (condResult ).WithSameMarks (trueResult ).WithSameMarks (falseResult ), diags
718
+ ref := cty .UnknownVal (cty .Number ).Refine ()
719
+ if trueRange .DefinitelyNotNull () && falseRange .DefinitelyNotNull () {
720
+ ref = ref .NotNull ()
721
+ }
722
+
723
+ falseLo , falseLoInc := falseRange .NumberLowerBound ()
724
+ falseHi , falseHiInc := falseRange .NumberUpperBound ()
725
+ trueLo , trueLoInc := trueRange .NumberLowerBound ()
726
+ trueHi , trueHiInc := trueRange .NumberUpperBound ()
727
+
728
+ if falseLo .IsKnown () && trueLo .IsKnown () {
729
+ lo , loInc := falseLo , falseLoInc
730
+ switch {
731
+ case trueLo .LessThan (falseLo ).True ():
732
+ lo , loInc = trueLo , trueLoInc
733
+ case trueLo .Equals (falseLo ).True ():
734
+ loInc = trueLoInc || falseLoInc
735
+ }
736
+
737
+ ref = ref .NumberRangeLowerBound (lo , loInc )
738
+ }
739
+
740
+ if falseHi .IsKnown () && trueHi .IsKnown () {
741
+ hi , hiInc := falseHi , falseHiInc
742
+ switch {
743
+ case trueHi .GreaterThan (falseHi ).True ():
744
+ hi , hiInc = trueHi , trueHiInc
745
+ case trueHi .Equals (falseHi ).True ():
746
+ hiInc = trueHiInc || falseHiInc
718
747
}
748
+ ref = ref .NumberRangeUpperBound (hi , hiInc )
719
749
}
750
+
751
+ return ref .NewValue ().WithMarks (resMarks ), diags
720
752
}
753
+
721
754
if trueResult .Type ().IsCollectionType () && falseResult .Type ().IsCollectionType () {
722
755
if trueResult .Type ().Equals (falseResult .Type ()) {
723
- if ! (trueResult .IsNull () || falseResult .IsNull ()) {
724
- trueLen := trueResult .Length ()
725
- falseLen := falseResult .Length ()
726
- if gt := trueLen .GreaterThan (falseLen ); gt .IsKnown () {
727
- b := cty .UnknownVal (resultType ).Refine ()
728
- trueLen , _ := trueLen .AsBigFloat ().Int64 ()
729
- falseLen , _ := falseLen .AsBigFloat ().Int64 ()
730
- if gt .True () {
731
- b = b .
732
- CollectionLengthLowerBound (int (falseLen )).
733
- CollectionLengthUpperBound (int (trueLen ))
734
- } else {
735
- b = b .
736
- CollectionLengthLowerBound (int (trueLen )).
737
- CollectionLengthUpperBound (int (falseLen ))
738
- }
739
- b = b .NotNull () // If neither of the results is null then the result can't be either
740
- return b .NewValue ().WithSameMarks (condResult ).WithSameMarks (trueResult ).WithSameMarks (falseResult ), diags
741
- }
756
+ ref := cty .UnknownVal (resultType ).Refine ()
757
+ if trueRange .DefinitelyNotNull () && falseRange .DefinitelyNotNull () {
758
+ ref = ref .NotNull ()
759
+ }
760
+
761
+ falseLo := falseRange .LengthLowerBound ()
762
+ falseHi := falseRange .LengthUpperBound ()
763
+ trueLo := trueRange .LengthLowerBound ()
764
+ trueHi := trueRange .LengthUpperBound ()
765
+
766
+ lo := falseLo
767
+ if trueLo < falseLo {
768
+ lo = trueLo
742
769
}
770
+
771
+ hi := falseHi
772
+ if trueHi > falseHi {
773
+ hi = trueHi
774
+ }
775
+
776
+ ref = ref .CollectionLengthLowerBound (lo ).CollectionLengthUpperBound (hi )
777
+ return ref .NewValue ().WithMarks (resMarks ), diags
743
778
}
744
779
}
745
- _ , condResultMarks := condResult .Unmark ()
746
- trueResult , trueResultMarks := trueResult .Unmark ()
747
- falseResult , falseResultMarks := falseResult .Unmark ()
748
780
749
- trueRng := trueResult .Range ()
750
- falseRng := falseResult .Range ()
751
781
ret := cty .UnknownVal (resultType )
752
- if trueRng .DefinitelyNotNull () && falseRng .DefinitelyNotNull () {
782
+ if trueRange .DefinitelyNotNull () && falseRange .DefinitelyNotNull () {
753
783
ret = ret .RefineNotNull ()
754
784
}
755
- return ret .WithMarks (condResultMarks , trueResultMarks , falseResultMarks ), diags
785
+ return ret .WithMarks (resMarks ), diags
756
786
}
787
+
757
788
condResult , err := convert .Convert (condResult , cty .Bool )
758
789
if err != nil {
759
790
diags = append (diags , & hcl.Diagnostic {
@@ -1244,9 +1275,9 @@ func (e *ObjectConsKeyExpr) UnwrapExpression() Expression {
1244
1275
1245
1276
// ForExpr represents iteration constructs:
1246
1277
//
1247
- // tuple = [for i, v in list: upper(v) if i > 2]
1248
- // object = {for k, v in map: k => upper(v)}
1249
- // object_of_tuples = {for v in list: v.key: v...}
1278
+ // tuple = [for i, v in list: upper(v) if i > 2]
1279
+ // object = {for k, v in map: k => upper(v)}
1280
+ // object_of_tuples = {for v in list: v.key: v...}
1250
1281
type ForExpr struct {
1251
1282
KeyVar string // empty if ignoring the key
1252
1283
ValVar string
@@ -1742,7 +1773,8 @@ func (e *SplatExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
1742
1773
if ty .IsListType () && sourceVal .Type ().IsCollectionType () {
1743
1774
// We can refine the length of an unknown list result based on
1744
1775
// the source collection's own length.
1745
- sourceRng := sourceVal .Range ()
1776
+ sv , _ := sourceVal .Unmark ()
1777
+ sourceRng := sv .Range ()
1746
1778
ret = ret .Refine ().
1747
1779
CollectionLengthLowerBound (sourceRng .LengthLowerBound ()).
1748
1780
CollectionLengthUpperBound (sourceRng .LengthUpperBound ()).
0 commit comments