internal/core/adt: dedup errors

Change-Id: I335f7d22c76fb16200b98f9c1f3c7e3712b267aa
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/9448
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Paul Jolly <paul@myitcv.org.uk>
diff --git a/cue/builtin_test.go b/cue/builtin_test.go
index aba1e14..20d92c8 100644
--- a/cue/builtin_test.go
+++ b/cue/builtin_test.go
@@ -62,13 +62,13 @@
 		`16`,
 	}, {
 		test("encoding/yaml", `yaml.Validate("a: 2\n---\na: 4", {a:<3})`),
-		`_|_(error in call to encoding/yaml.Validate: a: invalid value 4 (out of bound <3) (and 1 more errors))`,
+		`_|_(error in call to encoding/yaml.Validate: a: invalid value 4 (out of bound <3))`,
 	}, {
 		test("encoding/yaml", `yaml.Validate("a: 2\n---\na: 4", {a:<5})`),
 		`true`,
 	}, {
 		test("encoding/yaml", `yaml.Validate("a: 2\n", {a:<5, b:int})`),
-		`_|_(error in call to encoding/yaml.Validate: b: incomplete value int (and 1 more errors))`,
+		`_|_(error in call to encoding/yaml.Validate: b: incomplete value int)`,
 	}, {
 		test("strconv", `strconv.FormatUint(64, 16)`),
 		`"40"`,
@@ -77,7 +77,7 @@
 		`"foo"`,
 	}, {
 		test("regexp", `regexp.Find(#"f\w\w"#, "bar")`),
-		`_|_(error in call to regexp.Find: no match (and 1 more errors))`,
+		`_|_(error in call to regexp.Find: no match)`,
 	}, {
 		testExpr(`len([1, 2, 3])`),
 		`3`,
@@ -92,7 +92,7 @@
 			x: int
 			y: json.Marshal({a: x})
 		}`),
-		`{x:int,y:_|_(cannot convert incomplete value "int" to JSON (and 1 more errors))}`,
+		`{x:int,y:_|_(cannot convert incomplete value "int" to JSON)}`,
 	}, {
 		test("encoding/yaml", `yaml.MarshalStream([{a: 1}, {b: 2}])`),
 		`"a: 1\n---\nb: 2\n"`,
@@ -146,7 +146,7 @@
 		emit      string
 	}{{
 		test("list", `list.Sort([{a:1}, {b:2}], list.Ascending)`),
-		`_|_(error in call to list.Sort: less: invalid operands {b:2} and {a:1} to '<' (type struct and struct) (and 1 more errors))`,
+		`_|_(error in call to list.Sort: less: invalid operands {b:2} and {a:1} to '<' (type struct and struct))`,
 	}}
 	for i, tc := range testCases {
 		t.Run(fmt.Sprint(i), func(t *testing.T) {
diff --git a/internal/core/adt/context.go b/internal/core/adt/context.go
index 4c3b6d0..60e6b82 100644
--- a/internal/core/adt/context.go
+++ b/internal/core/adt/context.go
@@ -591,7 +591,9 @@
 				bb.Err = errors.Wrapf(b.Err, c.src.Pos(), "")
 				result = &bb
 			}
-			c.errs = CombineErrors(c.src, c.errs, result)
+			if c.errs != result {
+				c.errs = CombineErrors(c.src, c.errs, result)
+			}
 		}
 		if c.errs != nil {
 			result = c.errs
diff --git a/pkg/encoding/base64/testdata/gen.txtar b/pkg/encoding/base64/testdata/gen.txtar
index 5302a90..8ad720a 100644
--- a/pkg/encoding/base64/testdata/gen.txtar
+++ b/pkg/encoding/base64/testdata/gen.txtar
@@ -15,6 +15,6 @@
 Result:
 t1: "Zm9v"
 t2: 'foo'
-t3: _|_ // error in call to encoding/base64.Decode: illegal base64 data at input byte 0 (and 1 more errors)
-t4: _|_ // error in call to encoding/base64.Decode: base64: unsupported encoding: cannot use value {} (type struct) as null (and 1 more errors)
+t3: _|_ // error in call to encoding/base64.Decode: illegal base64 data at input byte 0
+t4: _|_ // error in call to encoding/base64.Decode: base64: unsupported encoding: cannot use value {} (type struct) as null
 
diff --git a/pkg/encoding/hex/testdata/gen.txtar b/pkg/encoding/hex/testdata/gen.txtar
index e25a0d5..45a951c 100644
--- a/pkg/encoding/hex/testdata/gen.txtar
+++ b/pkg/encoding/hex/testdata/gen.txtar
@@ -14,7 +14,7 @@
 Result:
 t1: "666f6f"
 t2: 'foo'
-t3: _|_ // error in call to encoding/hex.Decode: encoding/hex: invalid byte: U+006F 'o' (and 1 more errors)
+t3: _|_ // error in call to encoding/hex.Decode: encoding/hex: invalid byte: U+006F 'o'
 t4: """
 	00000000  66 6f 6f                                          |foo|
 
diff --git a/pkg/encoding/json/testdata/gen.txtar b/pkg/encoding/json/testdata/gen.txtar
index f54b900..5fd43a2 100644
--- a/pkg/encoding/json/testdata/gen.txtar
+++ b/pkg/encoding/json/testdata/gen.txtar
@@ -25,7 +25,7 @@
 import "encoding/json"
 
 t1: true
-t2: _|_ // error in call to encoding/json.Validate: a: invalid value 10 (out of bound <3) (and 1 more errors)
+t2: _|_ // error in call to encoding/json.Validate: a: invalid value 10 (out of bound <3)
 t3: true
 t4: "[1,2]"
 t5: """
diff --git a/pkg/encoding/yaml/testdata/gen.txtar b/pkg/encoding/yaml/testdata/gen.txtar
index 846b9a3..1cc0baf 100644
--- a/pkg/encoding/yaml/testdata/gen.txtar
+++ b/pkg/encoding/yaml/testdata/gen.txtar
@@ -23,10 +23,10 @@
     yaml.ValidatePartial:3:5
 
 Result:
-t1: _|_ // error in call to encoding/yaml.Validate: a: invalid value 4 (out of bound <3) (and 1 more errors)
+t1: _|_ // error in call to encoding/yaml.Validate: a: invalid value 4 (out of bound <3)
 t2: true
-t3: _|_ // error in call to encoding/yaml.Validate: b: incomplete value int (and 1 more errors)
-t4: _|_ // error in call to encoding/yaml.ValidatePartial: a: invalid value 4 (out of bound <3) (and 1 more errors)
+t3: _|_ // error in call to encoding/yaml.Validate: b: incomplete value int
+t4: _|_ // error in call to encoding/yaml.ValidatePartial: a: invalid value 4 (out of bound <3)
 t5: true
 t6: true
 t7: """
diff --git a/pkg/list/testdata/gen.txtar b/pkg/list/testdata/gen.txtar
index bb1a9ac..ef1d79f 100644
--- a/pkg/list/testdata/gen.txtar
+++ b/pkg/list/testdata/gen.txtar
@@ -79,14 +79,14 @@
     ./in.cue:46:24
     list:10:9
 Ascending.x: error in call to list.Sort: conflicting values string and {b:2} (mismatched types string and struct):
-    ./in.cue:46:24
+    ./in.cue:60:24
     list:10:18
 Ascending.y: error in call to list.Sort: 2 errors in empty disjunction:
 Ascending.y: error in call to list.Sort: conflicting values number and {a:1} (mismatched types number and struct):
-    ./in.cue:46:17
+    ./in.cue:60:17
     list:10:9
 Ascending.y: error in call to list.Sort: conflicting values string and {a:1} (mismatched types string and struct):
-    ./in.cue:60:17
+    ./in.cue:46:17
     list:10:18
 t3: cannot use "foo" (type string) as list in argument 1 to list.Avg:
     ./in.cue:5:14
@@ -107,41 +107,41 @@
 
 Result:
 t1: 2.5
-t2: _|_ // error in call to list.Avg: empty list (and 1 more errors)
+t2: _|_ // error in call to list.Avg: empty list
 t3: _|_ // t3: cannot use "foo" (type string) as list in argument 1 to list.Avg
 t4: [1, 2, 3, 4]
 t5: [3, 4]
 t6: []
-t7: _|_ // error in call to list.Drop: negative index (and 1 more errors)
+t7: _|_ // error in call to list.Drop: negative index
 t8: [1, 2, 3, 4]
 t9: [1, [[2, 3], []], [4]]
 t10: [1, [2, 3], [], 4]
 t11: [1, 2, 3, 4]
 t12: []
-t13: _|_ // error in call to list.FlattenN: cannot use value "foo" (type string) as list (and 1 more errors)
+t13: _|_ // error in call to list.FlattenN: cannot use value "foo" (type string) as list
 t14: _|_ // t14: cannot use "foo" (type string) as int in argument 2 to list.FlattenN
 t15: 4
-t16: _|_ // error in call to list.Max: empty list (and 1 more errors)
+t16: _|_ // error in call to list.Max: empty list
 t17: _|_ // t17: cannot use "foo" (type string) as list in argument 1 to list.Max
 t18: 1
-t19: _|_ // error in call to list.Min: empty list (and 1 more errors)
+t19: _|_ // error in call to list.Min: empty list
 t20: _|_ // t20: cannot use "foo" (type string) as list in argument 1 to list.Min
 t21: 24
 t22: 1
 t23: _|_ // t23: cannot use "foo" (type string) as list in argument 1 to list.Product
-t24: _|_ // error in call to list.Range: step must be non zero (and 1 more errors)
-t25: _|_ // error in call to list.Range: end must be greater than start when step is positive (and 1 more errors)
-t26: _|_ // error in call to list.Range: end must be less than start when step is negative (and 1 more errors)
+t24: _|_ // error in call to list.Range: step must be non zero
+t25: _|_ // error in call to list.Range: end must be greater than start when step is positive
+t26: _|_ // error in call to list.Range: end must be less than start when step is negative
 t27: [0, 1, 2, 3, 4]
 t28: [0]
 t29: [0, 2, 4]
 t30: [5, 4, 3, 2, 1]
 t31: [0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5]
 t32: [2, 3]
-t33: _|_ // error in call to list.Slice: negative index (and 1 more errors)
-t34: _|_ // error in call to list.Slice: invalid index: 3 > 1 (and 1 more errors)
-t35: _|_ // error in call to list.Slice: slice bounds out of range (and 1 more errors)
-t36: _|_ // error in call to list.Slice: slice bounds out of range (and 1 more errors)
+t33: _|_ // error in call to list.Slice: negative index
+t34: _|_ // error in call to list.Slice: invalid index: 3 > 1
+t35: _|_ // error in call to list.Slice: slice bounds out of range
+t36: _|_ // error in call to list.Slice: slice bounds out of range
 t37: []
 t38: [1, 2, 3, 4]
 t39: [{
@@ -154,19 +154,19 @@
 	a: 2
 	v: 1
 }]
-t40: _|_ // error in call to list.Sort: Ascending.x: 2 errors in empty disjunction: (and 11 more errors)
+t40: _|_ // error in call to list.Sort: Ascending.x: 2 errors in empty disjunction: (and 5 more errors)
 t41: ["a", "b"]
-t42: _|_ // t42: invalid type element 0 (int) of string list argument 0 (and 1 more errors)
+t42: _|_ // t42: invalid type element 0 (int) of string list argument 0
 t43: 10
 t44: 0
 t45: _|_ // t45: cannot use "foo" (type string) as list in argument 1 to list.Sum
 t46: []
 t47: [1, 2]
 t48: [1, 2, 3, 4]
-t49: _|_ // error in call to list.Take: negative index (and 1 more errors)
+t49: _|_ // error in call to list.Take: negative index
 t50: true
 t51: false
 t52: true
 t53: false
-t54: _|_ // error in call to list.Sort: Ascending.x: 2 errors in empty disjunction: (and 11 more errors)
+t54: _|_ // error in call to list.Sort: Ascending.x: 2 errors in empty disjunction: (and 5 more errors)
 
diff --git a/pkg/list/testdata/list.txtar b/pkg/list/testdata/list.txtar
index 5ebcd3a..e42e16c 100644
--- a/pkg/list/testdata/list.txtar
+++ b/pkg/list/testdata/list.txtar
@@ -89,7 +89,7 @@
 	t8: {
 		x: [1]
 		n: -1
-		v: _|_ // error in call to list.Repeat: negative count (and 1 more errors)
+		v: _|_ // error in call to list.Repeat: negative count
 	}
 }
 concat: {
@@ -123,7 +123,7 @@
 	}
 	t8: {
 		x: [1, [2]]
-		v: _|_ // error in call to list.Concat: cannot use value 1 (type int) as list (and 1 more errors)
+		v: _|_ // error in call to list.Concat: cannot use value 1 (type int) as list
 	}
 }
 unique: {
diff --git a/pkg/math/testdata/gen.txtar b/pkg/math/testdata/gen.txtar
index 268c96b..bb22999 100644
--- a/pkg/math/testdata/gen.txtar
+++ b/pkg/math/testdata/gen.txtar
@@ -36,9 +36,9 @@
 t1:  3.14159265358979323846264338327950288419716939937510582097494459
 t2:  3
 t3:  _|_ // t3: cannot call non-function math.Pi (type float)
-t6:  _|_ // error in call to math.Jacobi: big: invalid 2nd argument to Int.Jacobi: need odd integer but got 2000 (and 1 more errors)
+t6:  _|_ // error in call to math.Jacobi: big: invalid 2nd argument to Int.Jacobi: need odd integer but got 2000
 t7:  1
-t8:  _|_ // cannot use 2.0E+400 (type float) as float64 in argument 0 to math.Asin: value was rounded up (and 1 more errors)
+t8:  _|_ // cannot use 2.0E+400 (type float) as float64 in argument 0 to math.Asin: value was rounded up
 t16: 4096
 t17: 1e+4
 t18: true
diff --git a/pkg/math/testdata/round.txtar b/pkg/math/testdata/round.txtar
index ae9093c..adbdd8c 100644
--- a/pkg/math/testdata/round.txtar
+++ b/pkg/math/testdata/round.txtar
@@ -44,7 +44,7 @@
 mul0: true
 mul1: false
 // TODO(errors): ensure path is included for the following error.
-mul2:    _|_ // error in call to math.MultipleOf: division by zero (and 1 more errors)
+mul2:    _|_ // error in call to math.MultipleOf: division by zero
 mul3:    false
 mul4:    true
 mul5:    true
diff --git a/pkg/net/testdata/gen.txtar b/pkg/net/testdata/gen.txtar
index 5e06f72..4b41fdb 100644
--- a/pkg/net/testdata/gen.txtar
+++ b/pkg/net/testdata/gen.txtar
@@ -36,7 +36,7 @@
 t4:  "example.com:80"
 t5:  "[2001:db8::1]:80"
 t6:  "192.30.4.2:80"
-t7:  _|_ // error in call to net.JoinHostPort: invalid host [192, 30, 4] (and 1 more errors)
+t7:  _|_ // error in call to net.JoinHostPort: invalid host [192, 30, 4]
 t8:  true
 t9:  _|_ // t9: invalid value "23.23.23.2333" (does not satisfy net.IPv4)
 t10: true
diff --git a/pkg/path/testdata/error.txtar b/pkg/path/testdata/error.txtar
index 023994a..cfce2fa 100644
--- a/pkg/path/testdata/error.txtar
+++ b/pkg/path/testdata/error.txtar
@@ -26,5 +26,5 @@
 
 Result:
 joinOK:  "a/b"
-joinErr: _|_ // joinErr: cannot use "foo" as *"unix" | "windows" | "plan9" | "aix" | "android" | "darwin" | "dragonfly" | "freebsd" | "hurd" | "illumos" | "ios" | "js" | "linux" | "nacl" | "netbsd" | "openbsd" | "solaris" | "zos" in argument 2 to path.Join (and 3 more errors)
+joinErr: _|_ // joinErr: cannot use "foo" as *"unix" | "windows" | "plan9" | "aix" | "android" | "darwin" | "dragonfly" | "freebsd" | "hurd" | "illumos" | "ios" | "js" | "linux" | "nacl" | "netbsd" | "openbsd" | "solaris" | "zos" in argument 2 to path.Join (and 1 more errors)
 
diff --git a/pkg/regexp/testdata/gen.txtar b/pkg/regexp/testdata/gen.txtar
index 058d1c3..a34e36c 100644
--- a/pkg/regexp/testdata/gen.txtar
+++ b/pkg/regexp/testdata/gen.txtar
@@ -28,13 +28,13 @@
 
 Result:
 t1: "foo"
-t2: _|_ // error in call to regexp.Find: no match (and 1 more errors)
+t2: _|_ // error in call to regexp.Find: no match
 t3: ["foo", "flo"]
 t4: ["foo", "flo"]
-t5: _|_ // error in call to regexp.FindAll: no match (and 1 more errors)
+t5: _|_ // error in call to regexp.FindAll: no match
 t6: ["flo", "l", "o"]
 t7: [["flo", "l", "o"], ["foo", "o", "o"], ["fro", "r", "o"]]
-t8: _|_ // error in call to regexp.FindAllSubmatch: no match (and 1 more errors)
+t8: _|_ // error in call to regexp.FindAllSubmatch: no match
 t9: {
 	A: "l"
 	B: "o"
@@ -52,7 +52,7 @@
 t11: [{
 	A: ""
 }]
-t12: _|_ // error in call to regexp.FindAllNamedSubmatch: no match (and 1 more errors)
+t12: _|_ // error in call to regexp.FindAllNamedSubmatch: no match
 t13: "valid"
 t14: _|_ // t14: invalid value "invalid)" (does not satisfy regexp.Valid): error in call to regexp.Valid: error parsing regexp: unexpected ): `invalid)`
 
diff --git a/pkg/strconv/testdata/gen.txtar b/pkg/strconv/testdata/gen.txtar
index c18d09a..5deb5c7 100644
--- a/pkg/strconv/testdata/gen.txtar
+++ b/pkg/strconv/testdata/gen.txtar
@@ -19,8 +19,8 @@
 
 Result:
 t1: "40"
-t2: _|_ // int 300 overflows byte in argument 1 in call to strconv.FormatFloat (and 1 more errors)
-t3: _|_ // cannot use -1 (type int) as byte in argument 1 to strconv.FormatFloat (and 1 more errors)
+t2: _|_ // int 300 overflows byte in argument 1 in call to strconv.FormatFloat
+t3: _|_ // cannot use -1 (type int) as byte in argument 1 to strconv.FormatFloat
 t4: _|_ // t4: cannot use 1.0 (type float) as int in argument 2 to strconv.FormatFloat
 t5: "true"
 
diff --git a/pkg/strings/testdata/gen.txtar b/pkg/strings/testdata/gen.txtar
index b30bc7b..eb98510 100644
--- a/pkg/strings/testdata/gen.txtar
+++ b/pkg/strings/testdata/gen.txtar
@@ -43,7 +43,7 @@
 
 Result:
 t1: "Hello World!"
-t2: _|_ // t2: invalid type element 0 (int) of string list argument 0 (and 1 more errors)
+t2: _|_ // t2: invalid type element 0 (int) of string list argument 0
 t3: 97
 t4: 'llo'
 t5: "✓ H"