cue: fix issues related to '_'

Exporting didn't excape
'_' on the RHS did not always resolve to top.

Change-Id: I94350f6520ae815754c8e3fb1473e81ea562ab63
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/2861
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/ast.go b/cue/ast.go
index 6e394d3..eb2403d 100644
--- a/cue/ast.go
+++ b/cue/ast.go
@@ -360,6 +360,11 @@
 				break
 			}
 			v.sel, _ = ast.LabelName(x)
+			if v.sel == "_" {
+				if _, ok := x.(*ast.BasicLit); ok {
+					v.sel = "*"
+				}
+			}
 			attrs, err := createAttrs(v.ctx(), newNode(n), n.Attrs)
 			if err != nil {
 				return v.errf(n, err.format, err.args)
@@ -401,6 +406,11 @@
 
 	// Expressions
 	case *ast.Ident:
+		if n.Name == "_" {
+			ret = &top{newNode(n)}
+			break
+		}
+
 		if n.Node == nil {
 			if ret = v.resolve(n); ret != nil {
 				break
diff --git a/cue/export.go b/cue/export.go
index e8616e6..bb9969c 100644
--- a/cue/export.go
+++ b/cue/export.go
@@ -121,7 +121,7 @@
 func (p *exporter) label(f label) ast.Label {
 	orig := p.ctx.labelStr(f)
 	str := strconv.Quote(orig)
-	if len(orig)+2 < len(str) {
+	if len(orig)+2 < len(str) || (strings.HasPrefix(orig, "_") && f&1 == 0) {
 		return &ast.BasicLit{Value: str}
 	}
 	for i, r := range orig {
diff --git a/cue/export_test.go b/cue/export_test.go
index 51ad59e..b7b0de9 100644
--- a/cue/export_test.go
+++ b/cue/export_test.go
@@ -47,6 +47,18 @@
 			multiSep + "world" +
 			multiSep + `"""`,
 	}, {
+		in: `{
+			"_": int
+			"_foo": int
+			_bar: int
+		}`,
+		out: unindent(`
+		{
+			"_":    int
+			"_foo": int
+			_bar:   int
+		}`),
+	}, {
 		in: "{ a: 1, b: a + 2, c: null, d: true, e: _, f: string }",
 		out: unindent(`
 			{
diff --git a/cue/resolve_test.go b/cue/resolve_test.go
index 63b3520..dbbd01f 100644
--- a/cue/resolve_test.go
+++ b/cue/resolve_test.go
@@ -552,6 +552,9 @@
 
 func TestResolve(t *testing.T) {
 	testCases := []testCase{{
+		in:  `a: { <_>: _ }`,
+		out: `<0>{a: <1>{<>: <2>(_: string)->_, }}`,
+	}, {
 		in: `
 			a: b.c.d
 			b c: { d: 3 }