cue: apply wrapping to all errors in list
for valueError and callError.
This also improves path and position information.
Change-Id: I27edc7fef2e38e4017a9ee62c6f82f967c54d80a
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/7085
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cmd/cue/cmd/testdata/script/cmd_baddisplay.txt b/cmd/cue/cmd/testdata/script/cmd_baddisplay.txt
index 4defbf3..59f8451 100644
--- a/cmd/cue/cmd/testdata/script/cmd_baddisplay.txt
+++ b/cmd/cue/cmd/testdata/script/cmd_baddisplay.txt
@@ -3,7 +3,7 @@
cmp stderr cmd_baddisplay.out
-- cmd_baddisplay.out --
-command.baddisplay.display: conflicting values 42 and string (mismatched types int and string)
+command.baddisplay.display.text: conflicting values 42 and string (mismatched types int and string)
-- task.cue --
package home
message: "Hello world!"
diff --git a/cmd/cue/cmd/testdata/script/cmd_dep_cycle.txt b/cmd/cue/cmd/testdata/script/cmd_dep_cycle.txt
index 775d5e2..2f8ac7c 100644
--- a/cmd/cue/cmd/testdata/script/cmd_dep_cycle.txt
+++ b/cmd/cue/cmd/testdata/script/cmd_dep_cycle.txt
@@ -9,7 +9,7 @@
-- expect-stderr1 --
cyclic dependency in tasks
-- expect-stderr2 --
-command.aftercycle: structural cycle
+command.aftercycle.t1.$after.$after: structural cycle
-- expect-stderr3 --
-- interlocked-stdout --
v
diff --git a/cmd/cue/cmd/testdata/script/cmd_err.txt b/cmd/cue/cmd/testdata/script/cmd_err.txt
index 0ea7fba..3e11389 100644
--- a/cmd/cue/cmd/testdata/script/cmd_err.txt
+++ b/cmd/cue/cmd/testdata/script/cmd_err.txt
@@ -3,9 +3,10 @@
cmp stderr cmd_badfields.out
-- cmd_badfields.out --
-command.ref.task.display.filename: non-concrete value string
command.ref.task.display.contents: invalid bytes argument for field "contents": non-concrete value (string|bytes):
./task_tool.cue:6:8
+command.ref.task.display.filename: non-concrete value string:
+ tool/file:15:16
-- task_tool.cue --
package home
diff --git a/cmd/cue/cmd/testdata/script/eval_e.txt b/cmd/cue/cmd/testdata/script/eval_e.txt
index 933e006..7723916 100644
--- a/cmd/cue/cmd/testdata/script/eval_e.txt
+++ b/cmd/cue/cmd/testdata/script/eval_e.txt
@@ -4,7 +4,8 @@
-- expect-stdout --
-- expect-stderr --
-reference "nonExist" not found
+reference "nonExist" not found:
+ --expression:1:1
-- partial.cue --
package exitcode
diff --git a/cmd/cue/cmd/testdata/script/eval_expr.txt b/cmd/cue/cmd/testdata/script/eval_expr.txt
index 3a969c0..c4e103f 100644
--- a/cmd/cue/cmd/testdata/script/eval_expr.txt
+++ b/cmd/cue/cmd/testdata/script/eval_expr.txt
@@ -7,7 +7,7 @@
4
-- expect-stderr --
// b.idx
-invalid non-ground value string (must be concrete string)
+b.idx: invalid non-ground value string (must be concrete string)
-- partial.cue --
package partial
diff --git a/cue/errors.go b/cue/errors.go
index 1785167..1390f49 100644
--- a/cue/errors.go
+++ b/cue/errors.go
@@ -20,16 +20,16 @@
"cuelang.org/go/internal/core/adt"
)
-func (v Value) appendErr(err errors.Error, b *bottom) errors.Error {
- return &valueError{
- v: v,
- err: &adt.Bottom{
- Err: errors.Append(err, b.Err),
- },
- }
-}
-
func (v Value) toErr(b *bottom) (err errors.Error) {
+ errs := errors.Errors(b.Err)
+ if len(errs) > 1 {
+ for _, e := range errs {
+ bb := *b
+ bb.Err = e
+ err = errors.Append(err, &valueError{v: v, err: &bb})
+ }
+ return err
+ }
return &valueError{v: v, err: b}
}
@@ -48,6 +48,9 @@
}
func (e *valueError) Position() token.Pos {
+ if e.err.Err != nil {
+ return e.err.Err.Position()
+ }
src := e.err.Source()
if src == nil {
return token.NoPos
@@ -70,6 +73,12 @@
}
func (e *valueError) Path() (a []string) {
+ if e.err.Err != nil {
+ a = e.err.Err.Path()
+ if a != nil {
+ return a
+ }
+ }
return e.v.appendPath(nil)
}
diff --git a/internal/filetypes/filetypes_test.go b/internal/filetypes/filetypes_test.go
index a998a03..646ca60 100644
--- a/internal/filetypes/filetypes_test.go
+++ b/internal/filetypes/filetypes_test.go
@@ -19,6 +19,7 @@
"testing"
"cuelang.org/go/cue/build"
+ "cuelang.org/go/cue/errors"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
)
@@ -26,7 +27,7 @@
func check(t *testing.T, want, x interface{}, err error) {
t.Helper()
if err != nil {
- x = err.Error()
+ x = errors.String(err.(errors.Error))
}
if !cmp.Equal(x, want, cmpopts.EquateEmpty()) {
t.Error(cmp.Diff(want, x))
diff --git a/pkg/encoding/yaml/manual.go b/pkg/encoding/yaml/manual.go
index 60b7318..4c8c05c 100644
--- a/pkg/encoding/yaml/manual.go
+++ b/pkg/encoding/yaml/manual.go
@@ -31,6 +31,8 @@
if err := v.Validate(); err != nil {
return "", err
}
+ // TODO: allow adt.Bottom to implement errors.Error so that code and
+ // messages can be passed.
return "", internal.ErrIncomplete
}
n := v.Syntax(cue.Final(), cue.Concrete(true))
@@ -55,6 +57,8 @@
if err := v.Validate(); err != nil {
return "", err
}
+ // TODO: allow adt.Bottom to implement errors.Error so that code and
+ // messages can be passed.
return "", internal.ErrIncomplete
}
n := v.Syntax(cue.Final(), cue.Concrete(true))
diff --git a/pkg/internal/errors.go b/pkg/internal/errors.go
index fe11de1..6f1b29d 100644
--- a/pkg/internal/errors.go
+++ b/pkg/internal/errors.go
@@ -39,11 +39,14 @@
func (c *CallCtxt) errf(src adt.Node, underlying error, format string, args ...interface{}) {
var errs errors.Error
+ var code adt.ErrorCode
if err, ok := underlying.(bottomer); ok {
- errs = err.Bottom().Err
+ b := err.Bottom()
+ errs = b.Err
+ code = b.Code
}
errs = errors.Wrapf(errs, c.ctx.Pos(), format, args...)
- c.Err = &callError{&adt.Bottom{Err: errs}}
+ c.Err = &callError{&adt.Bottom{Code: code, Err: errs}}
}
func (c *CallCtxt) errcf(src adt.Node, code adt.ErrorCode, format string, args ...interface{}) {
@@ -59,11 +62,13 @@
pos = src.Pos()
}
}
- const msg = "error in call to %s"
- return &adt.Bottom{
- Code: b.Code,
- Err: errors.Wrapf(b.Err, pos, msg, c.builtin.name(c.ctx)),
+ var err errors.Error
+ for _, e := range errors.Errors(b.Err) {
+ const msg = "error in call to %s"
+ err = errors.Append(err,
+ errors.Wrapf(e, pos, msg, c.builtin.name(c.ctx)))
}
+ return &adt.Bottom{Code: b.Code, Err: err}
}
func (c *CallCtxt) convertError(x interface{}, name string) *adt.Bottom {
diff --git a/pkg/list/testdata/gen.txtar b/pkg/list/testdata/gen.txtar
index 06f6daa..aae5247 100644
--- a/pkg/list/testdata/gen.txtar
+++ b/pkg/list/testdata/gen.txtar
@@ -76,7 +76,8 @@
error in call to list.Slice: slice bounds out of range
error in call to list.Take: negative index
0: error in call to list.SortStrings: element 0 of list argument 0: cannot use value 1 (type int) as string
-x: error in call to list.Sort: x: conflicting values string and {b:2} (mismatched types string and struct) (and 1 more errors)
+x: error in call to list.Sort: conflicting values string and {b:2} (mismatched types string and struct)
+y: error in call to list.Sort: conflicting values string and {a:1} (mismatched types string and struct)
t3: cannot use "foo" (type string) as list in argument 1 to list.Avg:
./in.cue:5:14
t14: cannot use "foo" (type string) as int in argument 2 to list.FlattenN:
@@ -265,7 +266,8 @@
}
}
t40: (_|_){
- // [eval] x: error in call to list.Sort: x: conflicting values string and {b:2} (mismatched types string and struct) (and 1 more errors)
+ // [eval] x: error in call to list.Sort: conflicting values string and {b:2} (mismatched types string and struct)
+ // y: error in call to list.Sort: conflicting values string and {a:1} (mismatched types string and struct)
}
t41: (#list){
0: (string){ "a" }
@@ -300,6 +302,7 @@
t52: (bool){ true }
t53: (bool){ false }
t54: (_|_){
- // [eval] x: error in call to list.Sort: x: conflicting values string and {b:2} (mismatched types string and struct) (and 1 more errors)
+ // [eval] x: error in call to list.Sort: conflicting values string and {b:2} (mismatched types string and struct)
+ // y: error in call to list.Sort: conflicting values string and {a:1} (mismatched types string and struct)
}
}