Skip to content

Commit a50fa63

Browse files
committed
internal/core/dep: distinghish inline structs
With an upcoming change, inline structs can be shared and reappropriated as regular structs in some cases. This means that the current algorithm, which assumes that inline structs are always local to the current field, is no longer correct. We modify the algorithm to prepare for this change. One aspect of this is isLocal, which checks whether the field references resolve to within the current scope of dependency analysis (by comparing to empty). Another change is that we now need to be more precise when it comes to checking whether a Vertex is rooted or not. We use IsDetached and MayAttach instead of Rooted for V3 in some cases. Finally, we are now more aggressive with taking the top reference, instead of an interstitial reference, as the representative reference. This results in better output even for V2 Changes: issue2247.txtar: appropriate simplication import.txtar: fixes an issue in v2 let2.txtar: the v3 output seems more correct, as the original reference is more important than the interstitial one. Issue #2854 Signed-off-by: Marcel van Lohuizen <[email protected]> Change-Id: I618bb38bc6cfe0200f6950a30063bc2fcfa31b34 Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1202268 Unity-Result: CUE porcuepine <[email protected]> TryBot-Result: CUEcueckoo <[email protected]> Reviewed-by: Matthew Sackman <[email protected]>
1 parent 99407a4 commit a50fa63

File tree

5 files changed

+75
-27
lines changed

5 files changed

+75
-27
lines changed

internal/core/dep/dep.go

+49-3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package dep
1717

1818
import (
1919
"cuelang.org/go/cue/errors"
20+
"cuelang.org/go/internal"
2021
"cuelang.org/go/internal/core/adt"
2122
)
2223

@@ -413,15 +414,37 @@ func (c *visitor) reportDependency(env *adt.Environment, ref adt.Resolver, v *ad
413414
reference = c.topRef
414415
}
415416

416-
if !v.Rooted() {
417+
inspect := false
418+
419+
if c.ctxt.Version == internal.DevVersion {
420+
inspect = v.IsDetached() || !v.MayAttach()
421+
} else {
422+
inspect = !v.Rooted()
423+
}
424+
425+
if inspect {
426+
// TODO: there is currently no way to inspect where a non-rooted node
427+
// originated from. As of EvalV3, we allow non-rooted nodes to be
428+
// structure shared. This makes them effectively rooted, with the
429+
// difference that there is an indirection in BaseValue for the
430+
// structure sharing. Nonetheless, this information is lost in the
431+
// internal API when traversing.
432+
433+
// As an alternative we now do not skip processing the node if we
434+
// an inlined, non-rooted node is associated with another node than
435+
// the one we are currently processing.
436+
437+
// If a node is internal, we need to further investigate any references.
438+
// If there are any, reference, even if it is otherwise not reported,
439+
// we report this reference.
417440
before := c.numRefs
418441
c.markInternalResolvers(env, ref, v)
419442
// TODO: this logic could probably be simplified if we let clients
420443
// explicitly mark whether to visit rootless nodes. Visiting these
421444
// may be necessary when substituting values.
422445
switch _, ok := ref.(*adt.FieldReference); {
423-
case !ok:
424-
// Do not report rootless nodes for selectors.
446+
case !ok && c.isLocal(env, ref):
447+
// Do not report rootless nodes for selectors.
425448
return
426449
case c.numRefs > before:
427450
// For FieldReferences that resolve to something we do not need
@@ -453,6 +476,9 @@ func (c *visitor) reportDependency(env *adt.Environment, ref adt.Resolver, v *ad
453476
}
454477
v = w
455478
}
479+
if len(c.pathStack) == 0 && c.topRef != nil {
480+
altRef = c.topRef
481+
}
456482

457483
// All resolvers are expressions.
458484
if p := importRef(ref.(adt.Expr)); p != nil {
@@ -476,6 +502,26 @@ func (c *visitor) reportDependency(env *adt.Environment, ref adt.Resolver, v *ad
476502
}
477503
}
478504

505+
// isLocal reports whether a non-rooted struct is an internal node or not.
506+
// If it is not, we need to further investigate any references.
507+
func (c *visitor) isLocal(env *adt.Environment, r adt.Resolver) bool {
508+
for {
509+
switch x := r.(type) {
510+
case *adt.FieldReference:
511+
for i := 0; i < int(x.UpCount); i++ {
512+
env = env.Up
513+
}
514+
return env.Vertex == empty
515+
case *adt.SelectorExpr:
516+
r, _ = x.X.(adt.Resolver)
517+
case *adt.IndexExpr:
518+
r, _ = x.X.(adt.Resolver)
519+
default:
520+
return env.Vertex == empty
521+
}
522+
}
523+
}
524+
479525
// TODO(perf): make this available as a property of vertices to avoid doing
480526
// work repeatedly.
481527
func hasLetParent(v *adt.Vertex) bool {

internal/core/dep/dep_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ func testVisit(t *testing.T, w io.Writer, ctxt *adt.OpContext, v *adt.Vertex, cf
116116
if i := d.Import(); i != nil {
117117
path := i.ImportPath.StringValue(ctxt)
118118
str = fmt.Sprintf("%q.%s", path, str)
119-
} else if !d.Node.Rooted() {
119+
} else if d.Node.IsDetached() {
120120
str = "**non-rooted**"
121121
}
122122

@@ -129,7 +129,7 @@ func testVisit(t *testing.T, w io.Writer, ctxt *adt.OpContext, v *adt.Vertex, cf
129129
// DO NOT REMOVE: for Testing purposes.
130130
func TestX(t *testing.T) {
131131
version := internal.DefaultVersion
132-
version = internal.DevVersion
132+
// version = internal.DevVersion // Uncomment for eval V3
133133
flags := cuedebug.Config{
134134
Sharing: true,
135135
LogEval: 1,

internal/core/dep/testdata/let2.txtar

+19
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,25 @@ a: b: {
2323
}
2424
-- out/dependencies/field --
2525
line reference path of resulting vertex
26+
-- out/dependencies-v3/all --
27+
line reference path of resulting vertex
28+
12: X1 => v.w
29+
13: X2 => v.w
30+
14: X3.w => v.w
31+
20: Y1 => v
32+
21: Y2 => v
33+
-- diff/-out/dependencies-v3/all<==>+out/dependencies/all --
34+
diff old new
35+
--- old
36+
+++ new
37+
@@ -2,5 +2,5 @@
38+
12: X1 => v.w
39+
13: X2 => v.w
40+
14: X3.w => v.w
41+
-7: v => v
42+
-8: v => v
43+
+20: Y1 => v
44+
+21: Y2 => v
2645
-- out/dependencies/all --
2746
line reference path of resulting vertex
2847
12: X1 => v.w

internal/core/export/testdata/selfcontained/import.txtar

+1-10
Original file line numberDiff line numberDiff line change
@@ -160,15 +160,6 @@ diff old new
160160
//cue:path: "mod.test/a/pkg".a.b
161161
let B = {
162162
c: {
163-
@@ -42,7 +45,7 @@
164-
let W = {
165-
a: _hidden_567475F3
166-
_hidden_567475F3: {
167-
- a: 1
168-
+ a: b
169-
}
170-
b: 1
171-
x: {
172163
-- diff/self/todo/p2 --
173164
Investigate differences.
174165
We assign p2, because the differences only appear with sharing off.
@@ -217,7 +208,7 @@ let F = {
217208
let W = {
218209
a: _hidden_567475F3
219210
_hidden_567475F3: {
220-
a: 1
211+
a: b
221212
}
222213
b: 1
223214
x: {

internal/core/export/testdata/selfcontained/issue2247.txtar

+4-12
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,8 @@ let P = {
4646
e: {
4747
out: c
4848
}.out
49-
f: {
50-
out: Q
51-
}.out
52-
g: {
53-
out: Q
54-
}.out
49+
f: Q
50+
g: Q
5551
h: {
5652
out: {
5753
r: {
@@ -98,12 +94,8 @@ f: {
9894
e: {
9995
out: c
10096
}.out
101-
f: {
102-
out: Q
103-
}.out
104-
g: {
105-
out: Q
106-
}.out
97+
f: Q
98+
g: Q
10799
h: {
108100
out: {
109101
r: {

0 commit comments

Comments
 (0)