cue: introduce more explict error types

Issue #52

Change-Id: Ib0ba1f2f500ab15351cfccce57ac35e72d181983
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/2206
Reviewed-by: Marcel van Lohuizen <mpvl@google.com>
diff --git a/cmd/cue/cmd/testdata/partial/eval_conc.out b/cmd/cue/cmd/testdata/partial/eval_conc.out
index 9437c40..3c83dc1 100644
--- a/cmd/cue/cmd/testdata/partial/eval_conc.out
+++ b/cmd/cue/cmd/testdata/partial/eval_conc.out
@@ -1,2 +1,2 @@
-: invalid non-ground value string (must be concrete int|string):
-    ./testdata/partial/partial.cue:7:7
+more than one element remaining (1 and 2):
+    ./testdata/partial/partial.cue:4:6
diff --git a/cue/builtin.go b/cue/builtin.go
index 8751ecb..fc22d07 100644
--- a/cue/builtin.go
+++ b/cue/builtin.go
@@ -421,7 +421,7 @@
 
 func (c *callCtxt) error(i int) error {
 	x := newValueRoot(c.ctx, c.args[i])
-	return x.Err()
+	return x.err()
 }
 
 func (c *callCtxt) list(i int) (a Iterator) {
diff --git a/cue/errors.go b/cue/errors.go
index afd89ae..3bf3dbb 100644
--- a/cue/errors.go
+++ b/cue/errors.go
@@ -51,7 +51,6 @@
 
 func (v Value) toErr(b *bottom) errors.Error {
 	return &valueError{
-		Message: errors.NewMessage(b.msg, nil),
 		v:       v,
 		err:     b,
 	}
@@ -61,14 +60,20 @@
 
 // A valueError is returned as a result of evaluating a value.
 type valueError struct {
-	errors.Message
-
 	v   Value
 	err *bottom
 }
 
+func (e *valueError) Error() string {
+	return fmt.Sprint(e.err)
+}
+
 func (e *valueError) Position() token.Pos {
-	return e.err.pos.Pos()
+	return e.err.Pos()
+}
+
+func (e *valueError) Positions() []token.Pos {
+	return e.err.Positions()
 }
 
 func (e *valueError) Path() (a []string) {
diff --git a/cue/errors/errors.go b/cue/errors/errors.go
index 019c71d..717cc89 100644
--- a/cue/errors/errors.go
+++ b/cue/errors/errors.go
@@ -299,17 +299,17 @@
 
 	for e := err; e != nil; e = xerrors.Unwrap(e) {
 		switch x := e.(type) {
-		case interface{ Position() token.Pos }:
-			if pos := x.Position().String(); pos != "-" {
-				positions = append(positions, pos)
-			}
-
 		case interface{ Positions() []token.Pos }:
 			for _, p := range x.Positions() {
 				if p.IsValid() {
 					positions = append(positions, p.String())
 				}
 			}
+
+		case interface{ Position() token.Pos }:
+			if pos := x.Position().String(); pos != "-" {
+				positions = append(positions, pos)
+			}
 		}
 	}
 
diff --git a/cue/instance.go b/cue/instance.go
index 62c5f40..219c548 100644
--- a/cue/instance.go
+++ b/cue/instance.go
@@ -237,8 +237,7 @@
 	for _, k := range path {
 		obj, err := v.structVal(ctx)
 		if err != nil {
-			v := err.(*bottom)
-			return Value{idx, &valueData{arc: arc{cache: v, v: v}}}
+			return Value{idx, &valueData{arc: arc{cache: err, v: err}}}
 		}
 		v = obj.Lookup(k)
 	}
diff --git a/cue/types.go b/cue/types.go
index f168f35..046a3c5 100644
--- a/cue/types.go
+++ b/cue/types.go
@@ -788,6 +788,14 @@
 
 // Err returns the error represented by v or nil v is not an error.
 func (v Value) Err() error {
+	if err := v.checkKind(v.ctx(), bottomKind); err != nil {
+		return v.toErr(err)
+	}
+	return nil
+}
+
+// TODO: make bottom not an error and then make this return *bottom.
+func (v Value) err() error {
 	// TODO(incomplete): change to not return an error for incomplete.
 	if err := v.checkKind(v.ctx(), bottomKind); err != nil {
 		return err
@@ -928,7 +936,7 @@
 	v, _ = v.Default()
 	ctx := v.ctx()
 	if err := v.checkKind(ctx, listKind); err != nil {
-		return Iterator{ctx: ctx}, err
+		return Iterator{ctx: ctx}, v.toErr(err)
 	}
 	l := v.eval(ctx).(*list)
 	return Iterator{ctx: ctx, val: v, iter: l, len: len(l.elem.arcs)}, nil
@@ -938,7 +946,7 @@
 func (v Value) Null() error {
 	v, _ = v.Default()
 	if err := v.checkKind(v.ctx(), nullKind); err != nil {
-		return err
+		return v.toErr(err)
 	}
 	return nil
 }
@@ -953,7 +961,7 @@
 	v, _ = v.Default()
 	ctx := v.ctx()
 	if err := v.checkKind(ctx, boolKind); err != nil {
-		return false, err
+		return false, v.toErr(err)
 	}
 	return v.eval(ctx).(*boolLit).b, nil
 }
@@ -963,7 +971,7 @@
 	v, _ = v.Default()
 	ctx := v.ctx()
 	if err := v.checkKind(ctx, stringKind); err != nil {
-		return "", err
+		return "", v.toErr(err)
 	}
 	return v.eval(ctx).(*stringLit).str, nil
 }
@@ -979,7 +987,7 @@
 	case *stringLit:
 		return []byte(x.str), nil
 	}
-	return nil, v.checkKind(ctx, bytesKind|stringKind)
+	return nil, v.toErr(v.checkKind(ctx, bytesKind|stringKind))
 }
 
 // Reader returns a new Reader if v is a string or bytes type and an error
@@ -993,7 +1001,7 @@
 	case *stringLit:
 		return strings.NewReader(x.str), nil
 	}
-	return nil, v.checkKind(ctx, stringKind|bytesKind)
+	return nil, v.toErr(v.checkKind(ctx, stringKind|bytesKind))
 }
 
 // TODO: distinguish between optional, hidden, etc. Probably the best approach
@@ -1001,7 +1009,7 @@
 // a structVal.
 
 // structVal returns an structVal or an error if v is not a struct.
-func (v Value) structVal(ctx *context) (structValue, error) {
+func (v Value) structVal(ctx *context) (structValue, *bottom) {
 	return v.structValOpts(ctx, options{
 		omitHidden:   true,
 		omitOptional: true,
@@ -1009,7 +1017,7 @@
 }
 
 // structVal returns an structVal or an error if v is not a struct.
-func (v Value) structValOpts(ctx *context, o options) (structValue, error) {
+func (v Value) structValOpts(ctx *context, o options) (structValue, *bottom) {
 	v, _ = v.Default()
 	if err := v.checkKind(ctx, structKind); err != nil {
 		return structValue{}, err
@@ -1062,7 +1070,7 @@
 	ctx := v.ctx()
 	obj, err := v.structValOpts(ctx, o)
 	if err != nil {
-		return Iterator{ctx: ctx}, err
+		return Iterator{ctx: ctx}, v.toErr(err)
 	}
 	return Iterator{ctx: ctx, val: v, iter: obj.n, len: len(obj.n.arcs)}, nil
 }
@@ -1076,7 +1084,8 @@
 	for _, k := range path {
 		obj, err := v.structVal(ctx)
 		if err != nil {
-			return newValueRoot(ctx, err.(*bottom))
+			// TODO: return a Value at the same location and a new error?
+			return newValueRoot(ctx, err)
 		}
 		v = obj.Lookup(k)
 	}
@@ -1318,18 +1327,18 @@
 	o := getOptions(opts)
 	list := errors.List{}
 	v.Walk(func(v Value) bool {
-		if err := v.Err(); err != nil {
+		if err := v.checkKind(v.ctx(), bottomKind); err != nil {
 			if !o.concrete && isIncomplete(v.eval(v.ctx())) {
 				return false
 			}
-			list.Add(err)
+			list.Add(v.toErr(err))
 			if len(list) > 50 {
 				return false // mostly to avoid some hypothetical cycle issue
 			}
 		}
 		if o.concrete {
 			if err := isGroundRecursive(v.ctx(), v.eval(v.ctx())); err != nil {
-				list.Add(err)
+				list.Add(v.toErr(err))
 			}
 		}
 		return true
@@ -1343,7 +1352,7 @@
 	return nil
 }
 
-func isGroundRecursive(ctx *context, v value) error {
+func isGroundRecursive(ctx *context, v value) *bottom {
 	switch x := v.(type) {
 	case *list:
 		for i := 0; i < len(x.elem.arcs); i++ {
@@ -1354,7 +1363,7 @@
 		}
 	default:
 		if !x.kind().isGround() {
-			return ctx.mkErr(v, "incomplete value %q", debugStr(ctx, v))
+			return ctx.mkErr(v, "incomplete value (%v)", debugStr(ctx, v))
 		}
 	}
 	return nil
diff --git a/cue/types_test.go b/cue/types_test.go
index 5e6ed27..e8a59c3 100644
--- a/cue/types_test.go
+++ b/cue/types_test.go
@@ -463,7 +463,7 @@
 	}}
 	for _, tc := range testCases {
 		t.Run(tc.value, func(t *testing.T) {
-			err := getInstance(t, tc.value).Value().Err()
+			err := getInstance(t, tc.value).Value().err()
 			checkErr(t, err, tc.err, "init")
 		})
 	}
@@ -638,7 +638,7 @@
 				}
 			}
 			v := obj.Lookup("non-existing")
-			checkErr(t, v.Err(), "not found", "non-existing")
+			checkErr(t, v.err(), "not found", "non-existing")
 		})
 	}
 }