Skip to content
This repository has been archived by the owner on Nov 18, 2021. It is now read-only.

Commit

Permalink
internal/core: don't resolve values into anonymous packages
Browse files Browse the repository at this point in the history
Non-CUE files are equivalent to a CUE file without a package
clause or an anonyous package clause (package _).

Identifier resolution should only happend across files of the
same package.

This can be a breaking change and we should probably introduce
this in its separate release, maybe even minor release (say v0.4).

Fixes #736

Change-Id: I28a0eb8618c2527b66c953c03e4bad695188654e
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/8925
Reviewed-by: Marcel van Lohuizen <[email protected]>
Reviewed-by: CUE cueckoo <[email protected]>
  • Loading branch information
mpvl committed Apr 8, 2021
1 parent c505c19 commit 5c2b281
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 4 deletions.
80 changes: 80 additions & 0 deletions cmd/cue/cmd/testdata/script/eval_resolve.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Issue #736
#
# references should never resolve to files of an
# anonymous package (no package or package _).

! cue eval data.yaml check.cue
cmp stderr out-stderr

! cue eval none.cue check.cue
cmp stderr out-stderr

! cue eval anon.cue check.cue
cmp stderr out-stderr

# TODO: allow this for now. Files without a package clause should not resolve
# across other files.
cue eval package.cue check.cue

-- data.yaml --
nodes:
- name: foo
childs:
- bar
- baz

- name: bar
parent: foo

- name: baz
parent: foo

-- none.cue --
nodes: [{
name: "foo"
childs: ["bar", "baz"]
}, {
name: "bar"
parent: "foo"
}, {
name: "baz"
parent: "foo"
}]

-- anon.cue --
// This is an explicitly declared anonymous package.
package _

nodes: [{
name: "foo"
childs: ["bar", "baz"]
}, {
name: "bar"
parent: "foo"
}, {
name: "baz"
parent: "foo"
}]

-- package.cue --
package list

nodes: [{
name: "foo"
childs: ["bar", "baz"]
}, {
name: "bar"
parent: "foo"
}, {
name: "baz"
parent: "foo"
}]

-- check.cue --
import "list"

#map: {for n in nodes {"\(n.name)": n}}

-- out-stderr --
#map: reference "nodes" not found:
./check.cue:3:17
4 changes: 4 additions & 0 deletions cue/testdata/definitions/files.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// fields of another.

-- in.cue --
package foo

#theme: {
color: string
ctermbg: string
Expand All @@ -20,6 +22,8 @@ light: #theme & {
}

-- box.cue --
package foo

#Config & {
console: dark
}
Expand Down
13 changes: 11 additions & 2 deletions internal/core/compile/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,9 +235,18 @@ func (c *compiler) popScope() {
func (c *compiler) compileFiles(a []*ast.File) *adt.Vertex { // Or value?
c.fileScope = map[adt.Feature]bool{}

// Populate file scope to handle unresolved references. Note that we do
// not allow aliases to be resolved across file boundaries.
// TODO(resolve): this is also done in the runtime package, do we need both?

// Populate file scope to handle unresolved references.
// Excluded from cross-file resolution are:
// - import specs
// - aliases
// - anything in an anonymous file
//
for _, f := range a {
if p := internal.GetPackageInfo(f); p.IsAnonymous() {
continue
}
for _, d := range f.Decls {
if f, ok := d.(*ast.Field); ok {
if id, ok := f.Label.(*ast.Ident); ok {
Expand Down
12 changes: 10 additions & 2 deletions internal/core/runtime/resolve.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,21 @@ import (
"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/build"
"cuelang.org/go/cue/errors"
"cuelang.org/go/internal"
)

// TODO(resolve): this is also done in compile, do we need both?
func (r *Runtime) ResolveFiles(p *build.Instance) (errs errors.Error) {
idx := r.index

// Link top-level declarations. As top-level entries get unified, an entry
// may be linked to any top-level entry of any of the files.
allFields := map[string]ast.Node{}
for _, file := range p.Files {
for _, d := range file.Decls {
for _, f := range p.Files {
if p := internal.GetPackageInfo(f); p.IsAnonymous() {
continue
}
for _, d := range f.Decls {
if f, ok := d.(*ast.Field); ok && f.Value != nil {
if ident, ok := f.Label.(*ast.Ident); ok {
allFields[ident.Name] = f.Value
Expand All @@ -39,6 +44,9 @@ func (r *Runtime) ResolveFiles(p *build.Instance) (errs errors.Error) {
}
}
for _, f := range p.Files {
if p := internal.GetPackageInfo(f); p.IsAnonymous() {
continue
}
err := resolveFile(idx, f, p, allFields)
errs = errors.Append(errs, err)
}
Expand Down
5 changes: 5 additions & 0 deletions internal/internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@ type PkgInfo struct {
Name string
}

// IsAnonymous reports whether the package is anonymous.
func (p *PkgInfo) IsAnonymous() bool {
return p.Name == "" || p.Name == "_"
}

func GetPackageInfo(f *ast.File) PkgInfo {
for i, d := range f.Decls {
switch x := d.(type) {
Expand Down

0 comments on commit 5c2b281

Please sign in to comment.