cue: add Selector.PkgPath

Also fixes bug in Path, which did not convert
hidden fields properly.

Change-Id: I02d2173b53642b0da1db0576d5d2717fc6cb6541
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/9444
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Paul Jolly <paul@myitcv.org.uk>
diff --git a/cue/path.go b/cue/path.go
index 5afaf2a..b5574c0 100644
--- a/cue/path.go
+++ b/cue/path.go
@@ -49,6 +49,13 @@
 	return sel.sel.kind() == adt.DefinitionLabel
 }
 
+// PkgPath reports the package path associated with a hidden label or "" if
+// this is not a hidden label.
+func (sel Selector) PkgPath() string {
+	h, _ := sel.sel.(scopedSelector)
+	return h.pkg
+}
+
 var (
 	// AnyField can be used to ask for any single label.
 	//
diff --git a/cue/path_test.go b/cue/path_test.go
index 334bb39..05de651 100644
--- a/cue/path_test.go
+++ b/cue/path_test.go
@@ -19,7 +19,7 @@
 	"testing"
 )
 
-func Test(t *testing.T) {
+func TestPaths(t *testing.T) {
 	var r Runtime
 	inst, _ := r.Compile("", `
 		#Foo:   a: b: 1
diff --git a/cue/query_test.go b/cue/query_test.go
index 5f147d6..6d75037 100644
--- a/cue/query_test.go
+++ b/cue/query_test.go
@@ -16,10 +16,14 @@
 
 import (
 	"bytes"
+	"io/ioutil"
 	"testing"
 
 	"cuelang.org/go/cue"
+	"cuelang.org/go/cue/cuecontext"
+	"cuelang.org/go/internal/cuetxtar"
 	"cuelang.org/go/internal/diff"
+	"github.com/rogpeppe/go-internal/txtar"
 )
 
 func TestLookupPath(t *testing.T) {
@@ -139,3 +143,51 @@
 	}
 	return inst.Value()
 }
+
+func TestHidden(t *testing.T) {
+	in := `
+-- cue.mod/module.cue --
+module: "example.com"
+
+-- in.cue --
+import "example.com/foo"
+
+a: foo.C
+b: _c
+_c: 2
+-- foo/foo.cue --
+package foo
+
+C: _d
+_d: 3
+		`
+
+	a := txtar.Parse([]byte(in))
+	dir, _ := ioutil.TempDir("", "*")
+	instance := cuetxtar.Load(a, dir)[0]
+	if instance.Err != nil {
+		t.Fatal(instance.Err)
+	}
+
+	v := cuecontext.New().BuildInstance(instance)
+
+	testCases := []struct {
+		path cue.Path
+		pkg  string
+	}{{
+		path: cue.ParsePath("a"),
+		pkg:  "example.com/foo",
+	}, {
+		path: cue.ParsePath("b"),
+		pkg:  "_",
+	}}
+	for _, tc := range testCases {
+		t.Run(tc.path.String(), func(t *testing.T) {
+			v := v.LookupPath(tc.path)
+			p := cue.Dereference(cue.Dereference(v)).Path().Selectors()
+			if got := p[len(p)-1].PkgPath(); got != tc.pkg {
+				t.Errorf("got %v; want %v", got, tc.pkg)
+			}
+		})
+	}
+}
diff --git a/cue/types.go b/cue/types.go
index e06cef0..5edb989 100644
--- a/cue/types.go
+++ b/cue/types.go
@@ -1491,9 +1491,15 @@
 		case adt.IntLabel:
 			a[i] = Selector{indexSelector(f)}
 
-		case adt.DefinitionLabel, adt.HiddenDefinitionLabel, adt.HiddenLabel:
+		case adt.DefinitionLabel:
 			a[i] = Selector{definitionSelector(f.SelectorString(v.idx))}
 
+		case adt.HiddenDefinitionLabel, adt.HiddenLabel:
+			a[i] = Selector{scopedSelector{
+				name: f.IdentString(v.idx),
+				pkg:  f.PkgID(v.idx),
+			}}
+
 		case adt.StringLabel:
 			a[i] = Selector{stringSelector(f.StringValue(v.idx))}
 		}