Skip to content

Commit c8e131d

Browse files
committed
cue: treat disjunctions as normal non-concrete values
This brings the implementation in line with the spec relating to the treatment of default values. Before getting a default resulted in a "multiple values remaining" error if the value was a disjunction. However, there is nothing special about such disjuctions compared to any other non-concrete value. Generating an error early resulted in some strange and sometimes spurious error messages. Issue #52 Change-Id: I221ff8affc6469b3caf633be0674dfd265ea8b0f Reviewed-on: https://cue-review.googlesource.com/c/cue/+/2680 Reviewed-by: Marcel van Lohuizen <[email protected]>
1 parent 1588fe0 commit c8e131d

File tree

10 files changed

+77
-84
lines changed

10 files changed

+77
-84
lines changed

cmd/cue/cmd/testdata/partial/eval_conc.out

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
sum: more than one element remaining (1 and 2):
1+
sum: incomplete value ((1 | 2)):
22
./testdata/partial/partial.cue:4:6
33
b.idx: invalid non-ground value string (must be concrete int|string):
44
./testdata/partial/partial.cue:7:9

cue/ast_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ func TestEmit(t *testing.T) {
291291
a: 8000 | 7080
292292
a: 7080 | int
293293
}`,
294-
out: `<0>{a: _|_((8000 | 7080):more than one element remaining (8000 and 7080))}`,
294+
out: `<0>{a: (8000 | 7080)}`,
295295
rw: evalFull,
296296
}}
297297
for _, tc := range testCases {

cue/eval.go

Lines changed: 26 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -318,43 +318,40 @@ func (x *disjunction) evalPartial(ctx *context) (result evaluated) {
318318
}
319319

320320
func (x *disjunction) manifest(ctx *context) (result evaluated) {
321-
var err, marked, unmarked1, unmarked2 evaluated
322-
for _, d := range x.values {
323-
// Because of the lazy evaluation strategy, we may still have
324-
// latent unification.
325-
if err := validate(ctx, d.val); err != nil {
326-
continue
327-
}
321+
values := make([]dValue, 0, len(x.values))
322+
validValue := false
323+
for _, dv := range x.values {
328324
switch {
329-
case d.marked:
330-
if marked != nil {
331-
// TODO: allow disjunctions to be returned as is.
332-
return ctx.mkErr(x, codeIncomplete, "more than one default remaining (%v and %v)", ctx.str(marked), ctx.str(d.val))
333-
}
334-
marked = d.val.(evaluated)
335-
case unmarked1 == nil:
336-
unmarked1 = d.val.(evaluated)
325+
case isBottom(dv.val):
326+
case dv.marked:
327+
values = append(values, dv)
337328
default:
338-
unmarked2 = d.val.(evaluated)
329+
validValue = true
339330
}
340331
}
341-
switch {
342-
case marked != nil:
343-
return marked
344-
345-
case unmarked2 != nil:
346-
return ctx.mkErr(x, codeIncomplete, "more than one element remaining (%v and %v)",
347-
ctx.str(unmarked1), ctx.str(unmarked2))
348332

349-
case unmarked1 != nil:
350-
return unmarked1
333+
switch {
334+
case len(values) > 0:
335+
// values contains all the valid defaults
336+
case !validValue:
337+
return x
338+
default:
339+
for _, dv := range x.values {
340+
dv.marked = false
341+
values = append(values, dv)
342+
}
343+
}
351344

352-
case err != nil:
353-
return err
345+
switch len(values) {
346+
case 0:
347+
return x
354348

355-
default:
356-
return ctx.mkErr(x, "empty disjunction")
349+
case 1:
350+
return values[0].val.evalPartial(ctx)
357351
}
352+
353+
x = &disjunction{x.baseValue, values, true}
354+
return x.normalize(ctx, x).val
358355
}
359356

360357
func (x *binaryExpr) evalPartial(ctx *context) (result evaluated) {

cue/evaluator.go

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,15 @@ func (c *context) manifest(v value) evaluated {
2020
return evaluated
2121
}
2222
outer:
23-
for {
24-
switch x := evaluated.(type) {
25-
case *disjunction:
26-
evaluated = x.manifest(c)
23+
switch x := evaluated.(type) {
24+
case *disjunction:
25+
evaluated = x.manifest(c)
2726

28-
case *list:
29-
return x.manifest(c)
27+
case *list:
28+
return x.manifest(c)
3029

31-
default:
32-
break outer
33-
}
30+
default:
31+
break outer
3432
}
3533
return evaluated
3634
}

cue/export.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -524,11 +524,7 @@ func (p *exporter) expr(v value) ast.Expr {
524524
list := &ast.ListLit{}
525525
var expr ast.Expr = list
526526
for _, e := range x.elem.arcs {
527-
if doEval(p.mode) {
528-
list.Elts = append(list.Elts, p.expr(e.v.evalPartial(p.ctx)))
529-
} else {
530-
list.Elts = append(list.Elts, p.expr(e.v))
531-
}
527+
list.Elts = append(list.Elts, p.expr(e.v))
532528
}
533529
max := maxNum(x.len)
534530
num, ok := max.(*numLit)

cue/export_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,8 @@ func TestExport(t *testing.T) {
160160
}`,
161161
out: unindent(`
162162
{
163-
a: 1 | 2 | *_|_
164-
b: [1 | 2 | *_|_]
163+
a: 1 | 2
164+
b: [1 | 2]
165165
}`),
166166
}, {
167167
raw: true,

cue/resolve_test.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,7 @@ func TestBasicRewrite(t *testing.T) {
518518
rewriteHelper(t, testCases, evalPartial)
519519
}
520520

521-
func TestChooseFirst(t *testing.T) {
521+
func TestChooseDefault(t *testing.T) {
522522
testCases := []testCase{{
523523
desc: "pick first",
524524
in: `
@@ -531,13 +531,15 @@ func TestChooseFirst(t *testing.T) {
531531
`,
532532
out: "<0>{a: 5, b: <1>{c: <2>{a: 2}}}",
533533
}, {
534+
// In this test, default results to bottom, meaning that the non-default
535+
// value remains.
534536
desc: "simple disambiguation conflict",
535537
in: `
536538
a: *"a" | "b"
537539
b: *"b" | "a"
538540
c: a & b
539541
`,
540-
out: `<0>{a: "a", b: "b", c: _|_(("a" | "b" | *_|_):more than one element remaining ("a" and "b"))}`,
542+
out: `<0>{a: "a", b: "b", c: ("a" | "b")}`,
541543
}, {
542544
desc: "associativity of defaults",
543545
in: `
@@ -547,7 +549,7 @@ func TestChooseFirst(t *testing.T) {
547549
x: a & b
548550
y: b & c
549551
`,
550-
out: `<0>{a: "a", b: "a", c: _|_((*"a" | *"b" | "c"):more than one default remaining ("a" and "b")), x: "a", y: _|_((*"a" | *"b" | "c"):more than one default remaining ("a" and "b"))}`,
552+
out: `<0>{a: "a", b: "a", c: (*"a" | *"b"), x: "a", y: (*"a" | *"b")}`,
551553
}}
552554
rewriteHelper(t, testCases, evalFull)
553555
}
@@ -1910,7 +1912,7 @@ func TestFullEval(t *testing.T) {
19101912
x: {a:1}|{a:2}
19111913
y: x & {a:3}
19121914
`,
1913-
out: `<0>{x: _|_((<1>{a: 1} | <2>{a: 2}):more than one element remaining ({a: 1} and {a: 2})), y: _|_((<3>.x & <4>{a: 3}):empty disjunction: {a: (1 & 3)})}`,
1915+
out: `<0>{x: (<1>{a: 1} | <2>{a: 2}), y: _|_((<3>.x & <4>{a: 3}):empty disjunction: {a: (1 & 3)})}`,
19141916
}, {
19151917
desc: "cannot resolve references that would be ambiguous",
19161918
in: `
@@ -1930,10 +1932,10 @@ func TestFullEval(t *testing.T) {
19301932
`a1: _|_(((*0 | 1) & (<1>.a3 - <1>.a2)):cycle detected), ` +
19311933
`a3: 1, ` +
19321934
`a2: _|_(((*0 | 1) & (<1>.a3 - <1>.a1)):cycle detected), ` +
1933-
`b1: _|_((0 | 1 | *_|_):more than one element remaining (0 and 1)), ` +
1934-
`b2: _|_((0 | 1 | *_|_):more than one element remaining (0 and 1)), ` +
1935-
`c1: _|_((<2>{a: 1, b: 2} | <3>{a: 2, b: 1} | *_|_):more than one element remaining ({a: 1, b: 2} and {a: 2, b: 1})), ` +
1936-
`c2: _|_((<4>{a: 2, b: 1} | <5>{a: 1, b: 2} | *_|_):more than one element remaining ({a: 2, b: 1} and {a: 1, b: 2}))}`,
1935+
`b1: (0 | 1), ` +
1936+
`b2: (0 | 1), ` +
1937+
`c1: (<2>{a: 1, b: 2} | <3>{a: 2, b: 1}), ` +
1938+
`c2: (<4>{a: 2, b: 1} | <5>{a: 1, b: 2})}`,
19371939
}}
19381940
rewriteHelper(t, testCases, evalFull)
19391941
}

doc/tutorial/basics/defaults.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,5 @@ protocol: *"udp" | "tcp"
2929
`$ cue eval defaults.cue`
3030
```
3131
replicas: 1
32-
protocol: "tcp" | "udp" | *_|_
32+
protocol: "tcp" | "udp"
3333
```

0 commit comments

Comments
 (0)