Skip to content

Commit 9dd0f82

Browse files
committed
cue: don't panic on Iterator.Selector.Index with lists
We had tests which covered calling Selector.Index, but none where the Selector came from a Value.List iterator. https://cuelang.org/cl/552171 changed Iterator.Selector to wrap the returned selector with a constraint type, which is necessary for a struct fields iterator to properly include any optional or required constraint type. However, this wrapping was added unconditionally, even when a selector has no constraint type such as a list element. Selector.Index would then type assert into indexSelector, which would no longer work due to the wrapping. The simplest fix is to skip wrapConstraint if there is no constraint type to wrap the selector with, which is the case with list elements. This way, we don't need to change Selector.Index at all, which somehow still needs to reach for the inner indexSelector value. Per Marcel, lists will eventually have constraint types too, so add a note in Selector.Index as a reminder to handle it properly. The godoc in Selector.Index also still referenced SelIndex. Rather than adding an entirely new test, expand TestList to check Index. Fixes #2692. Signed-off-by: Daniel Martí <[email protected]> Change-Id: I4daf8c23a685c413c88892fb309a83b6c7a76386 Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1172105 Unity-Result: CUE porcuepine <[email protected]> Reviewed-by: Roger Peppe <[email protected]> Reviewed-by: Marcel van Lohuizen <[email protected]> TryBot-Result: CUEcueckoo <[email protected]>
1 parent 8f796bf commit 9dd0f82

File tree

3 files changed

+15
-3
lines changed

3 files changed

+15
-3
lines changed

cue/path.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,11 @@ func (sel Selector) PkgPath() string {
198198
}
199199

200200
// Index returns the index of the selector. It panics
201-
// unless sel.Type is SelIndex.
201+
// unless sel.Type is IndexLabel.
202202
func (sel Selector) Index() int {
203+
// Note that lists will eventually have constraint types too,
204+
// and in that case sel.sel would be of type constraintSelector,
205+
// causing the type assertion below to fail.
203206
s, ok := sel.sel.(indexSelector)
204207
if !ok {
205208
panic("Index called on non-index selector")

cue/types.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,12 @@ func (i *Iterator) Value() Value {
248248

249249
// Selector reports the field label of this iteration.
250250
func (i *Iterator) Selector() Selector {
251-
return wrapConstraint(featureToSel(i.f, i.idx), fromArcType(i.arcType))
251+
sel := featureToSel(i.f, i.idx)
252+
// Only call wrapConstraint if there is any constraint type to wrap with.
253+
if ctype := fromArcType(i.arcType); ctype != 0 {
254+
sel = wrapConstraint(sel, ctype)
255+
}
256+
return sel
252257
}
253258

254259
// Label reports the label of the value if i iterates over struct fields and ""

cue/types_test.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -727,7 +727,11 @@ func TestList(t *testing.T) {
727727
checkFatal(t, err, tc.err, "init")
728728

729729
buf := []byte{'['}
730-
for l.Next() {
730+
for wantIdx := 0; l.Next(); wantIdx++ {
731+
// Ensure that we can get each index as well.
732+
if got := l.Selector().Index(); got != wantIdx {
733+
t.Errorf("Index got %v; want %v", got, wantIdx)
734+
}
731735
b, err := l.Value().MarshalJSON()
732736
checkFatal(t, err, tc.err, "list.Value")
733737
buf = append(buf, b...)

0 commit comments

Comments
 (0)