Skip to content

Commit

Permalink
internal/core/eval: dereference indirections earlier
Browse files Browse the repository at this point in the history
Some temporary fields, like comprehension bindings, add
an indirection to Vertices. Bugs may arise if these are not
properly unwrapped.

Lookup now derferences such indirections. Unwrap does
the same as a second line of defense.

Signed-off-by: Marcel van Lohuizen <[email protected]>

Change-Id: Ia7832ab48ecebbb8c3c9341f99203859a7418e2a
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/531093
Unity-Result: CUEcueckoo <[email protected]>
TryBot-Result: CUEcueckoo <[email protected]>
Reviewed-by: Paul Jolly <[email protected]>
  • Loading branch information
mpvl committed Jan 16, 2022
1 parent 9f6a40e commit c1bf550
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 41 deletions.
91 changes: 58 additions & 33 deletions cue/testdata/comprehensions/fields.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -6,53 +6,78 @@ module: "example.com"
-- in.cue --
import "strings"

#User: {
tags_str: string
tags_map: {
for k, v in strings.Split(tags_str, " ") {
"\(v)": string
}
"{a}": string
dynamic: {
for _, s in ["foo"] {
(s): 1
"\(s)bar": 2
}
}

user: {
#User
tags_str: "b {c}"
issue560: {
#User: {
tags_str: string
tags_map: {
for k, v in strings.Split(tags_str, " ") {
"\(v)": string
}
"{a}": string
}
}

user: {
#User
tags_str: "b {c}"
}
}
-- out/eval --
(struct){
#User: (#struct){
tags_str: (string){ string }
tags_map: (_|_){
// [incomplete] error in call to strings.Split: non-concrete value string:
// ./in.cue:6:22
"{a}": (string){ string }
}
dynamic: (struct){
foo: (int){ 1 }
foobar: (int){ 2 }
}
user: (#struct){
tags_str: (string){ "b {c}" }
tags_map: (#struct){
"{a}": (string){ string }
b: (string){ string }
"{c}": (string){ string }
issue560: (struct){
#User: (#struct){
tags_str: (string){ string }
tags_map: (_|_){
// [incomplete] error in call to strings.Split: non-concrete value string:
// ./in.cue:14:25
"{a}": (string){ string }
}
}
user: (#struct){
tags_str: (string){ "b {c}" }
tags_map: (#struct){
"{a}": (string){ string }
b: (string){ string }
"{c}": (string){ string }
}
}
}
}
-- out/compile --
--- in.cue
{
#User: {
tags_str: string
tags_map: {
for k, v in 〈import;strings〉.Split(〈1;tags_str〉, " ") {
"\(〈1;v〉)": string
}
"{a}": string
dynamic: {
for _, s in [
"foo",
] {
〈1;s〉: 1
"\(〈1;s〉)bar": 2
}
}
user: {
〈1;#User〉
tags_str: "b {c}"
issue560: {
#User: {
tags_str: string
tags_map: {
for k, v in 〈import;strings〉.Split(〈1;tags_str〉, " ") {
"\(〈1;v〉)": string
}
"{a}": string
}
}
user: {
〈1;#User〉
tags_str: "b {c}"
}
}
}
16 changes: 15 additions & 1 deletion internal/core/adt/composite.go
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ func Unwrap(v Value) Value {
if !ok {
return v
}
// b, _ := x.BaseValue.(*Bottom)
x = x.Indirect()
if n := x.state; n != nil && isCyclePlaceholder(x.BaseValue) {
if n.errs != nil && !n.errs.IsIncomplete() {
return n.errs
Expand All @@ -499,6 +499,19 @@ func Unwrap(v Value) Value {
return x.Value()
}

// Indirect unrolls indirections of Vertex values. These may be introduced,
// for instance, by temporary bindings such as comprehension values.
// It returns v itself if v does not point to another Vertex.
func (v *Vertex) Indirect() *Vertex {
for {
arc, ok := v.BaseValue.(*Vertex)
if !ok {
return v
}
v = arc
}
}

// OptionalType is a bit field of the type of optional constraints in use by an
// Acceptor.
type OptionalType int8
Expand Down Expand Up @@ -639,6 +652,7 @@ func (v *Vertex) IsList() bool {
func (v *Vertex) Lookup(f Feature) *Vertex {
for _, a := range v.Arcs {
if a.Label == f {
a = a.Indirect()
return a
}
}
Expand Down
11 changes: 4 additions & 7 deletions internal/core/adt/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -400,13 +400,7 @@ func (c *OpContext) Resolve(env *Environment, r Resolver) (*Vertex, *Bottom) {
return nil, arc.ChildErrors
}

for {
x, ok := arc.BaseValue.(*Vertex)
if !ok {
break
}
arc = x
}
arc = arc.Indirect()

return arc, err
}
Expand Down Expand Up @@ -761,6 +755,9 @@ func (c *OpContext) lookup(x *Vertex, pos token.Pos, l Feature, state VertexStat
}

a := x.Lookup(l)
if a != nil {
a = a.Indirect()
}

var hasCycle bool
outer:
Expand Down

0 comments on commit c1bf550

Please sign in to comment.