Skip to content

Commit dcb2a1f

Browse files
committed
cue/errors: add Wrap
introduces new internal wrapping error that allows harmonizing wrapped errors. Issue #52 Change-Id: I93844d4cc7592521b70b6402a9670a941c2f6dfc Reviewed-on: https://cue-review.googlesource.com/c/cue/+/9447 Reviewed-by: Marcel van Lohuizen <[email protected]>
1 parent 276ce26 commit dcb2a1f

File tree

18 files changed

+113
-52
lines changed

18 files changed

+113
-52
lines changed

cmd/cue/cmd/testdata/script/cmd_err.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ command.ref.task.display.filename: invalid string argument: non-concrete value s
1010
./task_tool.cue:6:8
1111
./task_tool.cue:7:9
1212
tool/file:15:3
13+
tool/file:15:16
1314
-- task_tool.cue --
1415
package home
1516

cmd/cue/cmd/testdata/script/cmd_errpos.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ command.prompter.contents: invalid bytes argument: non-concrete value string:
1212
command.prompter.filename: invalid string argument: non-concrete value string:
1313
./task_tool.cue:9:10
1414
tool/file:9:3
15+
tool/file:9:16
1516
-- task_tool.cue --
1617
package foo
1718

cmd/cue/cmd/testdata/script/export_err.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ cmp stderr expect-stderr
1313
a.b.2.c: incomplete value int
1414
out: invalid interpolation: undefined field d:
1515
./exporterr/export_err.cue:7:6
16+
./exporterr/export_err.cue:7:16
1617
-- expect-stdout --
1718
-- exporterr/export_err.cue --
1819
package exporterr

cmd/cue/cmd/testdata/script/vet_yaml.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ cmp stderr expect-stderr
44
-- expect-stderr --
55
phrases: invalid value "phrases:\n # A quote from Mark Twain.\n quote1:\n lang: en\n attribution: Mark Twain\n\n # A Norwegian proverb.\n proverb:\n lang: no\n text: Stemmen som sier at du ikke klarer det, lyver." (does not satisfy encoding/yaml.Validate({phrases:{},#Phrase:{lang:=~"^[a-zA-Z0-9-_]{2,}$" | false,text:!=""},#LanguageTag:=~"^[a-zA-Z0-9-_]{2,}$" | false})): error in call to encoding/yaml.Validate: incomplete value !="":
66
./yaml.cue:19:10
7+
./yaml.cue:11:17
78
./yaml.cue:21:10
89
-- yaml.cue --
910
import "encoding/yaml"

cue/errors/errors.go

Lines changed: 66 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -170,25 +170,77 @@ func Newf(p token.Pos, format string, args ...interface{}) Error {
170170
// Wrapf creates an Error with the associated position and message. The provided
171171
// error is added for inspection context.
172172
func Wrapf(err error, p token.Pos, format string, args ...interface{}) Error {
173-
a, ok := err.(list)
173+
pErr := &posError{
174+
pos: p,
175+
Message: NewMessage(format, args),
176+
}
177+
return Wrap(pErr, err)
178+
}
179+
180+
// Wrap creates a new error where child is a subordinate error of parent.
181+
// If child is list of Errors, the result will itself be a list of errors
182+
// where child is a subordinate error of each parent.
183+
func Wrap(parent Error, child error) Error {
184+
if child == nil {
185+
return parent
186+
}
187+
a, ok := child.(list)
174188
if !ok {
175-
return &posError{
176-
pos: p,
177-
Message: NewMessage(format, args),
178-
err: err,
179-
}
189+
return &wrapped{parent, child}
180190
}
181-
b := make([]Error, len(a))
191+
b := make(list, len(a))
182192
for i, err := range a {
183-
b[i] = &posError{
184-
pos: p,
185-
Message: NewMessage(format, args),
186-
err: err,
187-
}
193+
b[i] = &wrapped{parent, err}
194+
}
195+
return b
196+
}
197+
198+
type wrapped struct {
199+
main Error
200+
wrap error
201+
}
202+
203+
// Error implements the error interface.
204+
func (e *wrapped) Error() string {
205+
switch msg := e.main.Error(); {
206+
case e.wrap == nil:
207+
return msg
208+
case msg == "":
209+
return e.wrap.Error()
210+
default:
211+
return fmt.Sprintf("%s: %s", msg, e.wrap)
212+
}
213+
}
214+
215+
func (e *wrapped) Msg() (format string, args []interface{}) {
216+
return e.main.Msg()
217+
}
218+
219+
func (e *wrapped) Path() []string {
220+
if p := Path(e.main); p != nil {
221+
return p
222+
}
223+
return Path(e.wrap)
224+
}
225+
226+
func (e *wrapped) InputPositions() []token.Pos {
227+
return append(e.main.InputPositions(), Positions(e.wrap)...)
228+
}
229+
230+
func (e *wrapped) Position() token.Pos {
231+
if p := e.main.Position(); p != token.NoPos {
232+
return p
233+
}
234+
if wrap, ok := e.wrap.(Error); ok {
235+
return wrap.Position()
188236
}
189-
return list(b)
237+
return token.NoPos
190238
}
191239

240+
func (e *wrapped) Unwrap() error { return e.wrap }
241+
242+
func (e *wrapped) Cause() error { return e.wrap }
243+
192244
// Promote converts a regular Go error to an Error if it isn't already one.
193245
func Promote(err error, msg string) Error {
194246
switch x := err.(type) {
@@ -209,27 +261,11 @@ type posError struct {
209261
pos token.Pos
210262
inputs []token.Pos
211263
Message
212-
213-
// The underlying error that triggered this one, if any.
214-
err error
215264
}
216265

217-
func (e *posError) Path() []string { return Path(e.err) }
266+
func (e *posError) Path() []string { return nil }
218267
func (e *posError) InputPositions() []token.Pos { return e.inputs }
219268
func (e *posError) Position() token.Pos { return e.pos }
220-
func (e *posError) Unwrap() error { return e.err }
221-
func (e *posError) Cause() error { return e.err }
222-
223-
// Error implements the error interface.
224-
func (e *posError) Error() string {
225-
if e.err == nil {
226-
return e.Message.Error()
227-
}
228-
if e.Message.format == "" {
229-
return e.err.Error()
230-
}
231-
return fmt.Sprintf("%s: %s", e.Message.Error(), e.err)
232-
}
233269

234270
// Append combines two errors, flattening Lists as necessary.
235271
func Append(a, b Error) Error {

cue/testdata/eval/dynamic_field.txtar

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ parenExprRefEqual: {
2525
Errors:
2626
invalid interpolation: conflicting values 2 and 1:
2727
./in.cue:12:31
28+
./in.cue:12:34
29+
./in.cue:12:36
2830

2931
Result:
3032
(_|_){
@@ -40,6 +42,8 @@ Result:
4042
issue799: (_|_){
4143
// [eval] invalid interpolation: conflicting values 2 and 1:
4244
// ./in.cue:12:31
45+
// ./in.cue:12:34
46+
// ./in.cue:12:36
4347
key: (int){ &(>=-2147483648, <=2147483647, int) }
4448
}
4549
}

cue/testdata/fulleval/055_issue318.txtar

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,10 @@
4545
Errors:
4646
#T.out1: invalid interpolation: undefined field y:
4747
./in.cue:3:8
48+
./in.cue:3:24
4849
#T.out2: invalid interpolation: undefined field y:
4950
./in.cue:4:8
51+
./in.cue:4:15
5052
#T.vy: undefined field y:
5153
./in.cue:6:12
5254

@@ -61,10 +63,12 @@ Result:
6163
out1: (_|_){
6264
// [eval] #T.out1: invalid interpolation: undefined field y:
6365
// ./in.cue:3:8
66+
// ./in.cue:3:24
6467
}
6568
out2: (_|_){
6669
// [eval] #T.out2: invalid interpolation: undefined field y:
6770
// ./in.cue:4:8
71+
// ./in.cue:4:15
6872
}
6973
vx: (string){ string }
7074
vy: (_|_){

cue/testdata/interpolation/041_interpolation.txtar

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ e: _|_ // expression in interpolation must evaluate to a number kind or string (
3535
Errors:
3636
e: invalid interpolation: cannot use [] (type list) as type (bool|string|bytes|number):
3737
./in.cue:7:4
38+
./in.cue:7:7
3839

3940
Result:
4041
(_|_){
@@ -49,10 +50,12 @@ Result:
4950
u: (_|_){
5051
// [incomplete] u: invalid interpolation: non-concrete value _ (type _):
5152
// ./in.cue:5:4
53+
// ./in.cue:5:7
5254
}
5355
r: (_){ _ }
5456
e: (_|_){
5557
// [eval] e: invalid interpolation: cannot use [] (type list) as type (bool|string|bytes|number):
5658
// ./in.cue:7:4
59+
// ./in.cue:7:7
5760
}
5861
}

cue/testdata/interpolation/incomplete.txtar

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ out: """
2727
out: (_|_){
2828
// [incomplete] out: invalid interpolation: undefined field #d:
2929
// ./in.cue:8:6
30+
// ./in.cue:13:21
3031
}
3132
}
3233
-- out/compile --

cue/testdata/references/errors.txtar

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,12 @@ Result:
8080
r1: (_|_){
8181
// [incomplete] missingFieldNestedInInterpolation.r1: invalid interpolation: undefined field b:
8282
// ./references.cue:27:9
83+
// ./references.cue:27:14
8384
}
8485
r2: (_|_){
8586
// [incomplete] missingFieldNestedInInterpolation.r2: invalid interpolation: undefined field d:
8687
// ./references.cue:30:9
88+
// ./references.cue:30:14
8789
}
8890
}
8991
}

0 commit comments

Comments
 (0)