@@ -128,6 +128,10 @@ func ValueSemanticEqualitySetElements(ctx context.Context, req ValueSemanticEqua
128128 // Short circuit flag
129129 updatedElements := false
130130
131+ // The underlying loop will mutate priorValueElements to avoid keeping
132+ // duplicate semantically equal elements. Need the original length to avoid panicks
133+ originalPriorElementsLength := len (priorValueElements )
134+
131135 // Loop through proposed elements by delegating to the recursive semantic
132136 // equality logic. This ensures that recursion will catch a further
133137 // underlying element type has its semantic equality logic checked, even if
@@ -136,33 +140,44 @@ func ValueSemanticEqualitySetElements(ctx context.Context, req ValueSemanticEqua
136140 // Ensure new value always contains all of proposed new value
137141 newValueElements [idx ] = proposedNewValueElement
138142
139- if idx >= len ( priorValueElements ) {
143+ if idx >= originalPriorElementsLength {
140144 continue
141145 }
142146
143- elementReq := ValueSemanticEqualityRequest {
144- Path : req .Path .AtSetValue (proposedNewValueElement ),
145- PriorValue : priorValueElements [idx ],
146- ProposedNewValue : proposedNewValueElement ,
147- }
148- elementResp := & ValueSemanticEqualityResponse {
149- NewValue : elementReq .ProposedNewValue ,
150- }
147+ // Loop through all prior value elements and see if there are any semantically equal elements
148+ for pIdx , priorValue := range priorValueElements {
149+ elementReq := ValueSemanticEqualityRequest {
150+ Path : req .Path .AtSetValue (proposedNewValueElement ),
151+ PriorValue : priorValue ,
152+ ProposedNewValue : proposedNewValueElement ,
153+ }
154+ elementResp := & ValueSemanticEqualityResponse {
155+ NewValue : elementReq .ProposedNewValue ,
156+ }
151157
152- ValueSemanticEquality (ctx , elementReq , elementResp )
158+ ValueSemanticEquality (ctx , elementReq , elementResp )
153159
154- resp .Diagnostics .Append (elementResp .Diagnostics ... )
160+ resp .Diagnostics .Append (elementResp .Diagnostics ... )
155161
156- if resp .Diagnostics .HasError () {
157- return
158- }
162+ if resp .Diagnostics .HasError () {
163+ return
164+ }
159165
160- if elementResp .NewValue .Equal (elementReq .ProposedNewValue ) {
161- continue
162- }
166+ if elementResp .NewValue .Equal (elementReq .ProposedNewValue ) {
167+ // This prior value element didn't match, but there could be other elements that do
168+ continue
169+ }
170+
171+ // Prior state was kept, meaning that we found a semantically equal element
172+ updatedElements = true
163173
164- updatedElements = true
165- newValueElements [idx ] = elementResp .NewValue
174+ // Remove the semantically equal element from the slice of candidates
175+ priorValueElements = append (priorValueElements [:pIdx ], priorValueElements [pIdx + 1 :]... )
176+
177+ // Order doesn't matter, so we can just set the prior state element to this index
178+ newValueElements [idx ] = elementResp .NewValue
179+ break
180+ }
166181 }
167182
168183 // No changes required if the elements were not updated.
0 commit comments