cue: fix crash if yielded value is a disjunction
The value is not always a struct, it can also be
a disjunction of structs.
Now relies on regular unfication to produce an error.
Fixes #310
Change-Id: I60cefca9b55da826f057f6e46ab87e5f52b3aa45
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/5323
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/eval.go b/cue/eval.go
index 0d2eb24..41bd0ce 100644
--- a/cue/eval.go
+++ b/cue/eval.go
@@ -433,22 +433,21 @@
}
func (x *structComprehension) evalPartial(ctx *context) evaluated {
- st := &structLit{baseValue: x.baseValue}
+ var st evaluated = &structLit{baseValue: x.baseValue}
err := x.clauses.yield(ctx, func(v evaluated) *bottom {
- embed := v.evalPartial(ctx).(*structLit)
- embed, err := embed.expandFields(ctx)
- if err != nil {
- return err
+ embed := v.evalPartial(ctx)
+ if st, ok := embed.(*structLit); ok {
+ x, err := st.expandFields(ctx)
+ if err != nil {
+ return err
+ }
+ embed = x
}
res := binOp(ctx, x, opUnify, st, embed)
- switch u := res.(type) {
- case *bottom:
- return u
- case *structLit:
- st = u
- default:
- panic("unreachable")
+ if b, ok := res.(*bottom); ok {
+ return b
}
+ st = res
return nil
})
if err != nil {
diff --git a/cue/resolve_test.go b/cue/resolve_test.go
index 9f1e555..ccbd647 100644
--- a/cue/resolve_test.go
+++ b/cue/resolve_test.go
@@ -2842,7 +2842,7 @@
`,
out: `<0>{` +
`c1: <1>{bar: <2>{baz: 2}, baz: 2}, ` +
- `c2: _|_(<3>{bar: 1<3>.bar}:cannot embed value 1 of type int in struct)}`,
+ `c2: _|_(conflicting values {bar: 1} and 1 (mismatched types struct and int))}`,
}, {
desc: "don't bind to string labels",
in: `
@@ -2944,6 +2944,24 @@
}
`,
out: `<0>{Spec :: <1>C{_vars: <2>C{something: string}, data: <3>C{foo :: <4>C{use: string}, baz: <5>.Marshal (<6>._vars.something), foobar: <5>.Marshal (<7>.foo)}}, Val: <8>C{_vars: <9>C{something: "var-string"}, data: <10>C{foo :: <11>C{use: "var-string"}, baz: "\"var-string\"", foobar: "{\"use\":\"var-string\"}"}}}`,
+ }, {
+ desc: "issue312",
+ in: `
+ for x in [1] {
+ *close({}) | { [_]: null }
+ }
+ `,
+ out: `<0>{ <1>for _, x in [1] yield <2>{}, (*close (<3>{}) | <4>{[]: <5>(_: string)->null, })}`,
+ }, {
+ // TODO(eval): note that this behavior is incompatible with allowing
+ // non-struct as emit values. If we ever want to do this, we need to
+ // do it soon.
+ desc: "issue312",
+ in: `
+ y: *1 | {a: 2}
+ for x in [1] { y }
+ `,
+ out: `<0>{y: 1, a: 2}`,
}}
rewriteHelper(t, testCases, evalFull)
}
diff --git a/cue/value.go b/cue/value.go
index 0ebca64..3ba7d65 100644
--- a/cue/value.go
+++ b/cue/value.go
@@ -1163,28 +1163,22 @@
switch n.(type) {
case *bottom, *top:
- case *structLit:
+ default:
orig := x.comprehensions
x.comprehensions = incomplete
src := binSrc(x.Pos(), opUnify, x, n)
n = binOp(ctx, src, opUnifyUnchecked, x, n)
x.comprehensions = orig
-
- default:
- return nil, ctx.mkErr(x, n, "cannot embed value %s of type %s in struct", ctx.str(n), n.kind())
}
switch checked.(type) {
case *bottom, *top:
- case *structLit:
+ default:
orig := x.comprehensions
x.comprehensions = incomplete
src := binSrc(x.Pos(), opUnify, n, checked)
n = binOp(ctx, src, opUnify, x, checked)
x.comprehensions = orig
-
- default:
- return nil, ctx.mkErr(x, n, "cannot embed value %s of type %s in struct", ctx.str(n), n.kind())
}
switch v := n.(type) {