diff --git a/cmd/cue/cmd/testdata/script/cmd_baddisplay.txt b/cmd/cue/cmd/testdata/script/cmd_baddisplay.txt index 4defbf30b..59f845180 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 775d5e248..2f8ac7c2d 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 @@ cmp stderr expect-stderr3 -- 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 0ea7fbacf..3e1138995 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 933e00646..7723916bd 100644 --- a/cmd/cue/cmd/testdata/script/eval_e.txt +++ b/cmd/cue/cmd/testdata/script/eval_e.txt @@ -4,7 +4,8 @@ cmp stdout expect-stdout -- 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 3a969c0e7..c4e103f82 100644 --- a/cmd/cue/cmd/testdata/script/eval_expr.txt +++ b/cmd/cue/cmd/testdata/script/eval_expr.txt @@ -7,7 +7,7 @@ cmp stdout expect-stdout 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 1785167a5..1390f49ca 100644 --- a/cue/errors.go +++ b/cue/errors.go @@ -20,16 +20,16 @@ import ( "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) Error() string { } 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) Msg() (string, []interface{}) { } 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 a998a03f0..646ca608c 100644 --- a/internal/filetypes/filetypes_test.go +++ b/internal/filetypes/filetypes_test.go @@ -19,6 +19,7 @@ import ( "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 @@ import ( 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 60b7318a8..4c8c05cf2 100644 --- a/pkg/encoding/yaml/manual.go +++ b/pkg/encoding/yaml/manual.go @@ -31,6 +31,8 @@ func Marshal(v cue.Value) (string, error) { 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 @@ func MarshalStream(v cue.Value) (string, error) { 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 fe11de1c9..6f1b29dc8 100644 --- a/pkg/internal/errors.go +++ b/pkg/internal/errors.go @@ -39,11 +39,14 @@ func (e *callError) Error() string { 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 @@ func wrapCallErr(c *CallCtxt, b *adt.Bottom) *adt.Bottom { 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 06f6daadb..aae524722 100644 --- a/pkg/list/testdata/gen.txtar +++ b/pkg/list/testdata/gen.txtar @@ -76,7 +76,8 @@ error in call to list.Slice: negative index 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 @@ Result: } } 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 @@ Result: 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) } }