cue: pass on compile-time errors

Be more aggressive with compile-time errors.
These were currently burried in the data
and only surfaced when explicitly visited.

Change-Id: I690c5c20ea40b9a43117bce72770c8ee824f99da
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/3762
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/ast.go b/cue/ast.go
index 07c4d1a..a4ac89f 100644
--- a/cue/ast.go
+++ b/cue/ast.go
@@ -47,10 +47,8 @@
 	if isBottom(result) {
 		val := newValueRoot(v.ctx(), result)
 		v.errors = errors.Append(v.errors, val.toErr(result.(*bottom)))
-		return v.errors
 	}
-
-	return nil
+	return v.errors
 }
 
 type astVisitor struct {
diff --git a/cue/ast_test.go b/cue/ast_test.go
index 2b510ce..1517236 100644
--- a/cue/ast_test.go
+++ b/cue/ast_test.go
@@ -255,8 +255,11 @@
 			a: *1,
 			b: **1 | 2
 		`,
-		out: `<0>{a: _|_(preference mark not allowed at this position), ` +
-			`b: (*_|_(preference mark not allowed at this position) | 2)}`,
+		out: `a: preference mark not allowed at this position:
+    test:2:7
+b: preference mark not allowed at this position:
+    test:3:8
+<0>{}`,
 	}, {
 		in: `
 			a: int @foo(1,"str")
diff --git a/cue/build.go b/cue/build.go
index 532cdde..3a8712b 100644
--- a/cue/build.go
+++ b/cue/build.go
@@ -323,7 +323,8 @@
 		// inst.instance.inst = p
 		inst.Err = resolveFiles(idx, p)
 		for _, f := range files {
-			inst.insertFile(f)
+			err := inst.insertFile(f)
+			inst.Err = errors.Append(inst.Err, err)
 		}
 	}
 	inst.ImportPath = p.ImportPath
diff --git a/cue/build/instance.go b/cue/build/instance.go
index c0197a6..b8a792c 100644
--- a/cue/build/instance.go
+++ b/cue/build/instance.go
@@ -21,6 +21,7 @@
 	"unicode"
 
 	"cuelang.org/go/cue/ast"
+	"cuelang.org/go/cue/ast/astutil"
 	"cuelang.org/go/cue/errors"
 	"cuelang.org/go/cue/parser"
 	"cuelang.org/go/cue/token"
@@ -206,6 +207,9 @@
 // AddSyntax adds the given file to list of files for this instance. The package
 // name of the file must match the package name of the instance.
 func (inst *Instance) AddSyntax(file *ast.File) errors.Error {
+	astutil.Resolve(file, func(pos token.Pos, msg string, args ...interface{}) {
+		inst.Err = errors.Append(inst.Err, errors.Newf(pos, msg, args...))
+	})
 	_, pkg, pos := internal.PackageInfo(file)
 	if !inst.setPkg(pkg) && pkg != inst.PkgName {
 		err := errors.Newf(pos,
diff --git a/cue/build_test.go b/cue/build_test.go
index 832ceea..cd89e92 100644
--- a/cue/build_test.go
+++ b/cue/build_test.go
@@ -65,7 +65,7 @@
 		`),
 	}
 	pkg2 := &bimport{
-		"example.com/foo/pkg2",
+		"example.com/foo/pkg2:pkg",
 		files(`
 		package pkg
 
@@ -152,18 +152,18 @@
 			files(
 				`package test
 
-				import "example.com/foo/pkg2"
+				import "example.com/foo/pkg2:pkg"
 
 				"Hello \(pkg2.Number)!"`),
 		}),
-		`imported and not used: "example.com/foo/pkg2"`,
+		`imported and not used: "example.com/foo/pkg2:pkg" (and 1 more errors)`,
 		// `file0.cue:5:14: unresolved reference pkg2`,
 	}, {
 		insts(pkg2, &bimport{"",
 			files(
 				`package test
 
-				import "example.com/foo/pkg2"
+				import "example.com/foo/pkg2:pkg"
 
 				"Hello \(pkg.Number)!"`),
 		}),
diff --git a/cue/go_test.go b/cue/go_test.go
index e16017e..d0411b4 100644
--- a/cue/go_test.go
+++ b/cue/go_test.go
@@ -125,7 +125,7 @@
 	}, {
 		time.Date(2019, 4, 1, 0, 0, 0, 0, time.UTC), `"2019-04-01T00:00:00Z"`,
 	}}
-	inst := getInstance(t, "foo")
+	inst := getInstance(t, "{}")
 	b := ast.NewIdent("dummy")
 	for _, tc := range testCases {
 		ctx := inst.newContext()
@@ -228,7 +228,7 @@
 		time.Now, // a function
 		"_|_(unsupported Go type (func() time.Time))",
 	}}
-	inst := getInstance(t, "foo")
+	inst := getInstance(t, "{}")
 
 	for _, tc := range testCases {
 		ctx := inst.newContext()
diff --git a/cue/resolve_test.go b/cue/resolve_test.go
index f5db2a2..f3bac0a 100644
--- a/cue/resolve_test.go
+++ b/cue/resolve_test.go
@@ -28,6 +28,7 @@
 }
 
 func compileFile(t *testing.T, body string) (*context, *structLit) {
+	t.Helper()
 	ctx, inst, errs := compileInstance(t, body)
 	if errs != nil {
 		t.Fatal(errs)
diff --git a/cue/subsume_test.go b/cue/subsume_test.go
index 176b092..b95dd72 100644
--- a/cue/subsume_test.go
+++ b/cue/subsume_test.go
@@ -173,27 +173,29 @@
 
 		// Call
 		113: {subsumes: true, in: `
-			a: fn(),
-			b: fn()`,
+			a: fn()
+			b: fn()
+			fn: _`,
 		},
-		// TODO: allow subsumption of unevaluated values?
-		114: {subsumes: true, in: `
-			a: len(),
-			b: len(1)`,
+		114: {subsumes: false, in: `
+			a: fn(),
+			b: fn(1)
+			fn: _`,
 		},
 		115: {subsumes: true, in: `
 			a: fn(2)
-			b: fn(2)`,
+			b: fn(2)
+			fn: _`,
 		},
-		// TODO: allow subsumption of unevaluated values?
 		116: {subsumes: true, in: `
 			a: fn(number)
-			b: fn(2)`,
+			b: fn(2)
+			fn: _`,
 		},
-		// TODO: allow subsumption of unevaluated values?
-		117: {subsumes: true, in: `
+		117: {subsumes: false, in: `
 			a: fn(2)
-			b: fn(number)`,
+			b: fn(number)
+			fn: _`,
 		},
 
 		// TODO: allow subsumption of unevaluated values?
diff --git a/cue/types_test.go b/cue/types_test.go
index cc991f1..c892443 100644
--- a/cue/types_test.go
+++ b/cue/types_test.go
@@ -63,13 +63,13 @@
 		kind:           BottomKind,
 		incompleteKind: BottomKind,
 		concrete:       true,
-	}, { // TODO: should be error{
-		value:          `v: b`,
+	}, {
+		value:          `v: b, b: 1&2`,
 		kind:           BottomKind,
 		incompleteKind: BottomKind,
 		concrete:       true,
 	}, {
-		value:          `v: (b[a])`,
+		value:          `v: (b[a]), b: 1, a: 1`,
 		kind:           BottomKind,
 		incompleteKind: BottomKind,
 		concrete:       true,
@@ -79,7 +79,7 @@
 		kind:           BottomKind,
 		incompleteKind: BoolKind,
 	}, {
-		value:          `v: ([][b])`,
+		value:          `v: ([][b]), b: "d"`,
 		kind:           BottomKind,
 		incompleteKind: BottomKind,
 		concrete:       true,
@@ -1129,10 +1129,9 @@
 		t.Run(tc.desc, func(t *testing.T) {
 			r := Runtime{}
 			inst, err := r.Parse("validate", tc.in)
-			if err != nil {
-				t.Fatal(err)
+			if err == nil {
+				err = inst.Value().Validate(tc.opts...)
 			}
-			err = inst.Value().Validate(tc.opts...)
 			if gotErr := err != nil; gotErr != tc.err {
 				t.Errorf("got %v; want %v", err, tc.err)
 			}
diff --git a/doc/tutorial/basics/6_expressions/25_interpolfield.txt b/doc/tutorial/basics/6_expressions/25_interpolfield.txt
index 963828c..9c90fdf 100644
--- a/doc/tutorial/basics/6_expressions/25_interpolfield.txt
+++ b/doc/tutorial/basics/6_expressions/25_interpolfield.txt
@@ -1,5 +1,5 @@
-cue eval -i genfield.cue
-cmp stdout expect-stdout-cue
+! cue eval genfield.cue
+cmp stderr expect-stderr
 
 -- frontmatter.toml --
 title = "Interpolation of Field Names"
@@ -18,10 +18,6 @@
     butterAndCheese: hasButter && hasCheese
 }
 
--- expect-stdout-cue --
-sandwich: {
-    type:            "Cheese"
-    hasButter:       true
-    butterAndCheese: _|_ // reference "hasCheese" not found
-    hasCheese:       true
-}
+-- expect-stderr --
+sandwich.butterAndCheese: reference "hasCheese" not found:
+    ./genfield.cue:5:35
diff --git a/doc/tutorial/basics/6_expressions/80_coalesce.txt b/doc/tutorial/basics/6_expressions/80_coalesce.txt
index 783e6c9..41cd1e1 100644
--- a/doc/tutorial/basics/6_expressions/80_coalesce.txt
+++ b/doc/tutorial/basics/6_expressions/80_coalesce.txt
@@ -34,7 +34,7 @@
 b: *list[5] | "None"
 
 n: [null]
-v: *n[0]&string | "default"
+v: *(n[0]&string) | "default"
 
 -- expect-stdout-cue --
 list: ["Cat", "Mouse", "Dog"]