Skip to content
This repository has been archived by the owner on Nov 18, 2021. It is now read-only.

Commit

Permalink
cue: fix crash if yielded value is a disjunction
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
mpvl committed Mar 18, 2020
1 parent 38362f8 commit 5ad8510
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 21 deletions.
23 changes: 11 additions & 12 deletions cue/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -433,22 +433,21 @@ func (x *listComprehension) evalPartial(ctx *context) evaluated {
}

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 {
Expand Down
20 changes: 19 additions & 1 deletion cue/resolve_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2842,7 +2842,7 @@ func TestFullEval(t *testing.T) {
`,
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: `
Expand Down Expand Up @@ -2944,6 +2944,24 @@ func TestFullEval(t *testing.T) {
}
`,
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)
}
Expand Down
10 changes: 2 additions & 8 deletions cue/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -1163,28 +1163,22 @@ func (x *structLit) expandFields(ctx *context) (st *structLit, err *bottom) {

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) {
Expand Down

0 comments on commit 5ad8510

Please sign in to comment.