Skip to content

Commit c1bf550

Browse files
committed
internal/core/eval: dereference indirections earlier
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 <mpvl@golang.org> Change-Id: Ia7832ab48ecebbb8c3c9341f99203859a7418e2a Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/531093 Unity-Result: CUEcueckoo <cueckoo@cuelang.org> TryBot-Result: CUEcueckoo <cueckoo@cuelang.org> Reviewed-by: Paul Jolly <paul@myitcv.io>
1 parent 9f6a40e commit c1bf550

File tree

3 files changed

+77
-41
lines changed

3 files changed

+77
-41
lines changed

cue/testdata/comprehensions/fields.txtar

Lines changed: 58 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,53 +6,78 @@ module: "example.com"
66
-- in.cue --
77
import "strings"
88

9-
#User: {
10-
tags_str: string
11-
tags_map: {
12-
for k, v in strings.Split(tags_str, " ") {
13-
"\(v)": string
14-
}
15-
"{a}": string
9+
dynamic: {
10+
for _, s in ["foo"] {
11+
(s): 1
12+
"\(s)bar": 2
1613
}
1714
}
1815

19-
user: {
20-
#User
21-
tags_str: "b {c}"
16+
issue560: {
17+
#User: {
18+
tags_str: string
19+
tags_map: {
20+
for k, v in strings.Split(tags_str, " ") {
21+
"\(v)": string
22+
}
23+
"{a}": string
24+
}
25+
}
26+
27+
user: {
28+
#User
29+
tags_str: "b {c}"
30+
}
2231
}
2332
-- out/eval --
2433
(struct){
25-
#User: (#struct){
26-
tags_str: (string){ string }
27-
tags_map: (_|_){
28-
// [incomplete] error in call to strings.Split: non-concrete value string:
29-
// ./in.cue:6:22
30-
"{a}": (string){ string }
31-
}
34+
dynamic: (struct){
35+
foo: (int){ 1 }
36+
foobar: (int){ 2 }
3237
}
33-
user: (#struct){
34-
tags_str: (string){ "b {c}" }
35-
tags_map: (#struct){
36-
"{a}": (string){ string }
37-
b: (string){ string }
38-
"{c}": (string){ string }
38+
issue560: (struct){
39+
#User: (#struct){
40+
tags_str: (string){ string }
41+
tags_map: (_|_){
42+
// [incomplete] error in call to strings.Split: non-concrete value string:
43+
// ./in.cue:14:25
44+
"{a}": (string){ string }
45+
}
46+
}
47+
user: (#struct){
48+
tags_str: (string){ "b {c}" }
49+
tags_map: (#struct){
50+
"{a}": (string){ string }
51+
b: (string){ string }
52+
"{c}": (string){ string }
53+
}
3954
}
4055
}
4156
}
4257
-- out/compile --
4358
--- in.cue
4459
{
45-
#User: {
46-
tags_str: string
47-
tags_map: {
48-
for k, v in 〈import;strings〉.Split(〈1;tags_str〉, " ") {
49-
"\(〈1;v〉)": string
50-
}
51-
"{a}": string
60+
dynamic: {
61+
for _, s in [
62+
"foo",
63+
] {
64+
〈1;s〉: 1
65+
"\(〈1;s〉)bar": 2
5266
}
5367
}
54-
user: {
55-
〈1;#User〉
56-
tags_str: "b {c}"
68+
issue560: {
69+
#User: {
70+
tags_str: string
71+
tags_map: {
72+
for k, v in 〈import;strings〉.Split(〈1;tags_str〉, " ") {
73+
"\(〈1;v〉)": string
74+
}
75+
"{a}": string
76+
}
77+
}
78+
user: {
79+
〈1;#User〉
80+
tags_str: "b {c}"
81+
}
5782
}
5883
}

internal/core/adt/composite.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ func Unwrap(v Value) Value {
487487
if !ok {
488488
return v
489489
}
490-
// b, _ := x.BaseValue.(*Bottom)
490+
x = x.Indirect()
491491
if n := x.state; n != nil && isCyclePlaceholder(x.BaseValue) {
492492
if n.errs != nil && !n.errs.IsIncomplete() {
493493
return n.errs
@@ -499,6 +499,19 @@ func Unwrap(v Value) Value {
499499
return x.Value()
500500
}
501501

502+
// Indirect unrolls indirections of Vertex values. These may be introduced,
503+
// for instance, by temporary bindings such as comprehension values.
504+
// It returns v itself if v does not point to another Vertex.
505+
func (v *Vertex) Indirect() *Vertex {
506+
for {
507+
arc, ok := v.BaseValue.(*Vertex)
508+
if !ok {
509+
return v
510+
}
511+
v = arc
512+
}
513+
}
514+
502515
// OptionalType is a bit field of the type of optional constraints in use by an
503516
// Acceptor.
504517
type OptionalType int8
@@ -639,6 +652,7 @@ func (v *Vertex) IsList() bool {
639652
func (v *Vertex) Lookup(f Feature) *Vertex {
640653
for _, a := range v.Arcs {
641654
if a.Label == f {
655+
a = a.Indirect()
642656
return a
643657
}
644658
}

internal/core/adt/context.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -400,13 +400,7 @@ func (c *OpContext) Resolve(env *Environment, r Resolver) (*Vertex, *Bottom) {
400400
return nil, arc.ChildErrors
401401
}
402402

403-
for {
404-
x, ok := arc.BaseValue.(*Vertex)
405-
if !ok {
406-
break
407-
}
408-
arc = x
409-
}
403+
arc = arc.Indirect()
410404

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

763757
a := x.Lookup(l)
758+
if a != nil {
759+
a = a.Indirect()
760+
}
764761

765762
var hasCycle bool
766763
outer:

0 commit comments

Comments
 (0)