cue: fix handling of incomplete calls
This fixes template.Execute. The fix is more general by
detecting incomplete values in marshalErrors returned by
any builtin.
JSON and YAML marshaling was already okay.
Closes #314
Change-Id: I6cd92a7f589b7d42eaf40e47a2cd23f55cc7b43a
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/5421
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/builtin.go b/cue/builtin.go
index 098a5b2..4a680bb 100644
--- a/cue/builtin.go
+++ b/cue/builtin.go
@@ -288,6 +288,7 @@
if err := recover(); err != nil {
errVal = err
}
+ const msg = "error in call to %s: %v"
switch err := errVal.(type) {
case nil:
case *callError:
@@ -296,15 +297,18 @@
if err, ok := err.Err.(*marshalError); ok && err.b != nil {
ret = err.b
}
+ case *marshalError:
+ ret = err.b
+ ret = ctx.mkErr(src, x, ret, msg, x.name(ctx), err)
case *valueError:
ret = err.err
- ret = ctx.mkErr(src, x, ret, "error in call to %s: %v", x.name(ctx), err)
+ ret = ctx.mkErr(src, x, ret, msg, x.name(ctx), err)
default:
if call.err == internal.ErrIncomplete {
ret = ctx.mkErr(src, codeIncomplete, "incomplete value")
} else {
// TODO: store the underlying error explicitly
- ret = ctx.mkErr(src, x, "error in call to %s: %v", x.name(ctx), err)
+ ret = ctx.mkErr(src, x, msg, x.name(ctx), err)
}
}
}()
diff --git a/cue/builtin_test.go b/cue/builtin_test.go
index 1c8df6e..3480268 100644
--- a/cue/builtin_test.go
+++ b/cue/builtin_test.go
@@ -452,6 +452,12 @@
test("encoding/json", `json.MarshalStream([{a: 1}, {b: 2}])`),
`"{\"a\":1}\n{\"b\":2}\n"`,
}, {
+ test("encoding/json", `{
+ x: int
+ y: json.Marshal({a: x})
+ }`),
+ `{x: int, y: Marshal ({a: x})}`,
+ }, {
test("encoding/yaml", `yaml.MarshalStream([{a: 1}, {b: 2}])`),
`"a: 1\n---\nb: 2\n"`,
}, {
@@ -654,8 +660,8 @@
test("time", `time.Unix(1500000000, 123456)`),
`"2017-07-14T02:40:00.000123456Z"`,
}}
- for _, tc := range testCases {
- t.Run("", func(t *testing.T) {
+ for i, tc := range testCases {
+ t.Run(fmt.Sprint(i), func(t *testing.T) {
insts := Build(makeInstances(tc.instances))
if err := insts[0].Err; err != nil {
t.Fatal(err)
diff --git a/cue/resolve_test.go b/cue/resolve_test.go
index f8c8857..95f8e29 100644
--- a/cue/resolve_test.go
+++ b/cue/resolve_test.go
@@ -2980,6 +2980,41 @@
`out2: _|_(<3>.arg.y:undefined field "y"), ` +
`vx: string, ` +
`vy: _|_(<3>.arg.y:undefined field "y")}}`,
+ }, {
+ desc: "issue314",
+ in: `
+ import (
+ "text/template"
+ "encoding/yaml"
+ "encoding/json"
+ )
+
+ x: {
+ s: "myname"
+ T
+ }
+
+ T :: {
+ s: string
+ out: template.Execute("{{.s}}", {
+ "s": s
+ })
+ }
+
+ V :: {
+ s: string
+ out: json.Marshal({"s": s})
+ }
+
+ U :: {
+ s: string
+ out: yaml.Marshal({"s": s})
+ }`,
+ out: `<0>{` +
+ `T :: <1>C{s: string, out: <2>.Execute ("{{.s}}",<3>C{s: <4>.s})}, ` +
+ `x: <5>C{s: "myname", out: "myname"}, ` +
+ `V :: <6>C{s: string, out: <7>.Marshal (<8>C{s: <9>.s})}, ` +
+ `U :: <10>C{s: string, out: <11>.Marshal (<12>C{s: <13>.s})}}`,
}}
rewriteHelper(t, testCases, evalFull)
}