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)
   }
 }