cue: tighten API of comprehensions

When *bottom implemented error, it was a bad idea
to return it as an error (nil-interface issue).
Not it does not, it can safely be done while improving
the API.

Change-Id: Ie6451fca4172cf408de9e0f58d7931a9d7344450
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/3182
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/errors.go b/cue/errors.go
index 9ab8bb3..a3ce783 100644
--- a/cue/errors.go
+++ b/cue/errors.go
@@ -262,7 +262,7 @@
 	return n.kind() == bottomKind
 }
 
-func firstBottom(v ...value) evaluated {
+func firstBottom(v ...value) *bottom {
 	for _, b := range v {
 		if isBottom(b) {
 			return b.(*bottom)
diff --git a/cue/eval.go b/cue/eval.go
index 5b4a56c..bb4399f 100644
--- a/cue/eval.go
+++ b/cue/eval.go
@@ -258,7 +258,7 @@
 func (x *listComprehension) evalPartial(ctx *context) evaluated {
 	s := &structLit{baseValue: x.baseValue}
 	list := &list{baseValue: x.baseValue, elem: s}
-	result := x.clauses.yield(ctx, func(k, v evaluated, _, _ bool) *bottom {
+	err := x.clauses.yield(ctx, func(k, v evaluated, _, _ bool) *bottom {
 		if !k.kind().isAnyOf(intKind) {
 			return ctx.mkErr(k, "key must be of type int")
 		}
@@ -268,12 +268,8 @@
 		})
 		return nil
 	})
-	switch {
-	case result == nil:
-	case isBottom(result):
-		return result
-	default:
-		panic("should not happen")
+	if err != nil {
+		return err
 	}
 	list.initLit()
 	return list
diff --git a/cue/value.go b/cue/value.go
index 8ce8537..524bc1b 100644
--- a/cue/value.go
+++ b/cue/value.go
@@ -804,7 +804,7 @@
 	newArcs := []arc{}
 
 	for _, c := range comprehensions {
-		result := c.clauses.yield(ctx, func(k, v evaluated, opt, def bool) *bottom {
+		err := c.clauses.yield(ctx, func(k, v evaluated, opt, def bool) *bottom {
 			if !k.kind().isAnyOf(stringKind) {
 				return ctx.mkErr(k, "key must be of type string")
 			}
@@ -833,12 +833,8 @@
 			})
 			return nil
 		})
-		switch {
-		case result == nil:
-		case isBottom(result):
-			return nil, result.(*bottom)
-		default:
-			panic("should not happen")
+		if err != nil {
+			return nil, err
 		}
 	}
 
@@ -1380,14 +1376,14 @@
 }
 
 func (x *fieldComprehension) kind() kind {
-	return topKind | nonGround
+	return structKind | nonGround
 }
 
 type yieldFunc func(k, v evaluated, optional, definition bool) *bottom
 
 type yielder interface {
 	value
-	yield(*context, yieldFunc) evaluated
+	yield(*context, yieldFunc) *bottom
 }
 
 type yield struct {
@@ -1400,19 +1396,19 @@
 
 func (x *yield) kind() kind { return topKind | referenceKind }
 
-func (x *yield) yield(ctx *context, fn yieldFunc) evaluated {
+func (x *yield) yield(ctx *context, fn yieldFunc) *bottom {
 	var k evaluated
 	if x.key != nil {
 		k = ctx.manifest(x.key)
-		if isBottom(k) {
-			return k
+		if err, ok := k.(*bottom); ok {
+			return err
 		}
 	} else {
 		k = &top{}
 	}
 	v := x.value.evalPartial(ctx)
-	if isBottom(v) {
-		return v
+	if err, ok := v.(*bottom); ok {
+		return err
 	}
 	if err := fn(k, v, x.opt, x.def); err != nil {
 		return err
@@ -1428,10 +1424,10 @@
 
 func (x *guard) kind() kind { return topKind | referenceKind }
 
-func (x *guard) yield(ctx *context, fn yieldFunc) evaluated {
+func (x *guard) yield(ctx *context, fn yieldFunc) *bottom {
 	filter := ctx.manifest(x.condition)
-	if isBottom(filter) {
-		return filter
+	if err, ok := filter.(*bottom); ok {
+		return err
 	}
 	if err := checkKind(ctx, filter, boolKind); err != nil {
 		return err
@@ -1452,7 +1448,7 @@
 
 func (x *feed) kind() kind { return topKind | referenceKind }
 
-func (x *feed) yield(ctx *context, yfn yieldFunc) (result evaluated) {
+func (x *feed) yield(ctx *context, yfn yieldFunc) (result *bottom) {
 	if ctx.trace {
 		defer uni(indent(ctx, "feed", x))
 	}
@@ -1474,8 +1470,8 @@
 			}
 			val := src.at(ctx, i)
 			v := fn.call(ctx, x, key, val)
-			if isBottom(v) {
-				return v.evalPartial(ctx)
+			if err, ok := v.(*bottom); ok {
+				return err
 			}
 			if err := v.(yielder).yield(ctx, yfn); err != nil {
 				return err
@@ -1488,8 +1484,8 @@
 			idx := newNum(x, intKind)
 			idx.v.SetInt64(int64(i))
 			v := fn.call(ctx, x, idx, src.at(ctx, i))
-			if isBottom(v) {
-				return v.evalPartial(ctx)
+			if err, ok := v.(*bottom); ok {
+				return err
 			}
 			if err := v.(yielder).yield(ctx, yfn); err != nil {
 				return err
@@ -1498,8 +1494,8 @@
 		return nil
 
 	default:
-		if isBottom(source) {
-			return source
+		if err, ok := source.(*bottom); ok {
+			return err
 		}
 		if k := source.kind(); k&(structKind|listKind) == bottomKind {
 			return ctx.mkErr(x, x.source, "feed source must be list or struct, found %s", k)