Skip to content

Commit c558da0

Browse files
committedOct 8, 2024·
internal/core/adt: use depth counters for ancestor tracking
This change uses depth counters to be able to find ancestor nodes that are currently being processed. The old mechanism used the evaluatingArcs status to determine this, as well as walking up the parent tree. The new mechanism replaces evaluatingArcs, but also tracks some parent nodes where the Parent field may not be set. For instance, when computing an inline struct, the parent node is not set (it is non rooted), but for the purpose of cycle detection, the computing node should be seen as a parent. We keep the use of evaluatingArcs around for now as a definsive mechanism and remove it in a later CL to allow finding possible negative consequences in a bisection. Issue #2854 Signed-off-by: Marcel van Lohuizen <mpvl@gmail.com> Change-Id: I958905711a8bbcdb51b862c6ee60da06f1d9972c Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1202217 TryBot-Result: CUEcueckoo <cueckoo@cuelang.org> Reviewed-by: Matthew Sackman <matthew@cue.works> Unity-Result: CUE porcuepine <cue.porcuepine@gmail.com>
1 parent 16df890 commit c558da0

File tree

6 files changed

+107
-96
lines changed

6 files changed

+107
-96
lines changed
 

‎cue/testdata/benchmarks/issue1684.txtar

+14-14
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,15 @@ nestedClosed: passing: {
6262
D: {id: {}} | {[string]: D}
6363
}
6464
-- out/evalalpha/stats --
65-
Leaks: 3341
66-
Freed: 794
67-
Reused: 794
68-
Allocs: 3341
65+
Leaks: 2135
66+
Freed: 530
67+
Reused: 530
68+
Allocs: 2135
6969
Retain: 0
7070

71-
Unifications: 937
72-
Conjuncts: 6553
73-
Disjuncts: 1414
71+
Unifications: 475
72+
Conjuncts: 4333
73+
Disjuncts: 790
7474
-- out/evalalpha --
7575
(struct){
7676
#Secret: (#struct){
@@ -143,18 +143,18 @@ diff old new
143143
-Freed: 1064333
144144
-Reused: 1064282
145145
-Allocs: 51
146-
+Leaks: 3341
147-
+Freed: 794
148-
+Reused: 794
149-
+Allocs: 3341
146+
+Leaks: 2135
147+
+Freed: 530
148+
+Reused: 530
149+
+Allocs: 2135
150150
Retain: 0
151151

152152
-Unifications: 792123
153153
-Conjuncts: 2480117
154154
-Disjuncts: 1064333
155-
+Unifications: 937
156-
+Conjuncts: 6553
157-
+Disjuncts: 1414
155+
+Unifications: 475
156+
+Conjuncts: 4333
157+
+Disjuncts: 790
158158
-- diff/-out/evalalpha<==>+out/eval --
159159
diff old new
160160
--- old

‎cue/testdata/cycle/comprehension.txtar

+8-8
Original file line numberDiff line numberDiff line change
@@ -310,10 +310,10 @@ issue2367: {
310310
}
311311

312312
-- out/evalalpha/stats --
313-
Leaks: 782
314-
Freed: 60
315-
Reused: 60
316-
Allocs: 782
313+
Leaks: 779
314+
Freed: 63
315+
Reused: 63
316+
Allocs: 779
317317
Retain: 0
318318

319319
Unifications: 499
@@ -913,10 +913,10 @@ diff old new
913913
-Reused: 1260
914914
-Allocs: 60
915915
-Retain: 145
916-
+Leaks: 782
917-
+Freed: 60
918-
+Reused: 60
919-
+Allocs: 782
916+
+Leaks: 779
917+
+Freed: 63
918+
+Reused: 63
919+
+Allocs: 779
920920
+Retain: 0
921921

922922
-Unifications: 832

‎cue/testdata/cycle/evaluate.txtar

+37-49
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ letCycleFail.t1.a.X: structural cycle:
135135
./in.cue:33:11
136136
disjunctionCycle.b: cannot use 1 (type int) as list in argument 1 to and:
137137
./in.cue:56:9
138+
b: structural cycle:
139+
./in.cue:62:6
138140
closeCycle.d: structural cycle:
139141
./in.cue:73:11
140142
embedCycle: structural cycle:
@@ -226,11 +228,13 @@ Result:
226228
#A: (_|_){
227229
// [structural cycle]
228230
a: (_|_){
229-
// [structural cycle]
231+
// [structural cycle] b: structural cycle:
232+
// ./in.cue:62:6
230233
}
231234
}
232235
#B: (_|_){
233-
// [structural cycle]
236+
// [structural cycle] b: structural cycle:
237+
// ./in.cue:62:6
234238
}
235239
}
236240
letCycleWithAnd: (struct){
@@ -345,51 +349,51 @@ Result:
345349
diff old new
346350
--- old
347351
+++ new
348-
@@ -1,47 +1,47 @@
352+
@@ -1,47 +1,49 @@
349353
Errors:
350354
-closeCycle.a: structural cycle
351355
-closeCycle.b.d: structural cycle
352-
+printCycle.a.X: structural cycle
353-
+structCycle.c: structural cycle
354-
+letCycleOK.t2.a.X: structural cycle:
355-
+ ./in.cue:23:11
356-
+letCycleFail.t1.a.X: structural cycle:
357-
+ ./in.cue:33:11
358-
+disjunctionCycle.b: cannot use 1 (type int) as list in argument 1 to and:
359-
+ ./in.cue:56:9
360-
+closeCycle.d: structural cycle:
361-
+ ./in.cue:73:11
362-
+embedCycle: structural cycle:
363-
+ ./in.cue:85:12
364-
+listAddCycle.0.0: structural cycle:
365-
+ ./in.cue:91:5
366-
+listMulCycle.0.a.b: structural cycle:
367-
+ ./in.cue:97:5
368-
closeFail.x.b: field not allowed:
369-
+ ./in.cue:105:6
370-
./in.cue:104:6
356+
-closeFail.x.b: field not allowed:
357+
- ./in.cue:104:6
371358
- ./in.cue:105:12
372359
- ./in.cue:106:6
373-
./in.cue:107:5
360+
- ./in.cue:107:5
374361
-letCycleFail.t1.a.c: structural cycle
375362
-structCycle.a: structural cycle
376363
-structCycle.b.d: structural cycle
377364
-disjunctionCycle.a: cannot use 1 (type int) as list in argument 1 to and:
378365
- ./in.cue:56:9
379-
-disjunctionCycle.b: cannot use 1 (type int) as list in argument 1 to and:
380-
- ./in.cue:56:9
366+
+printCycle.a.X: structural cycle
367+
+structCycle.c: structural cycle
368+
+letCycleOK.t2.a.X: structural cycle:
369+
+ ./in.cue:23:11
370+
+letCycleFail.t1.a.X: structural cycle:
371+
+ ./in.cue:33:11
372+
disjunctionCycle.b: cannot use 1 (type int) as list in argument 1 to and:
373+
./in.cue:56:9
381374
-disjunctionCycle.c: cannot use 1 (type int) as list in argument 1 to and:
382375
- ./in.cue:56:9
383-
-b: structural cycle:
384-
- ./in.cue:62:6
376+
b: structural cycle:
377+
./in.cue:62:6
385378
-closeCycle.c: structural cycle:
386379
- ./in.cue:73:15
387380
-structCycle.c: structural cycle:
388381
- ./in.cue:79:14
389-
-embedCycle: structural cycle:
382+
+closeCycle.d: structural cycle:
383+
+ ./in.cue:73:11
384+
embedCycle: structural cycle:
390385
- ./in.cue:85:11
391386
-printCycle.a.X.X: structural cycle:
392387
- ./in.cue:113:6
388+
+ ./in.cue:85:12
389+
+listAddCycle.0.0: structural cycle:
390+
+ ./in.cue:91:5
391+
+listMulCycle.0.a.b: structural cycle:
392+
+ ./in.cue:97:5
393+
+closeFail.x.b: field not allowed:
394+
+ ./in.cue:105:6
395+
+ ./in.cue:104:6
396+
+ ./in.cue:107:5
393397

394398
Result:
395399
(_|_){
@@ -420,7 +424,7 @@ diff old new
420424
}
421425
}
422426
}
423-
@@ -56,20 +56,16 @@
427+
@@ -56,20 +58,16 @@
424428
// [structural cycle] letCycleFail.t1.a.X: structural cycle
425429
}
426430
c: (_|_){
@@ -451,7 +455,7 @@ diff old new
451455
}
452456
x: (struct){
453457
y: (string){ "" }
454-
@@ -85,15 +81,15 @@
458+
@@ -85,15 +83,15 @@
455459
disjunctionCycle: (_|_){
456460
// [eval]
457461
a: (_|_){
@@ -476,23 +480,7 @@ diff old new
476480
// ./in.cue:56:9
477481
}
478482
}
479-
@@ -102,13 +98,11 @@
480-
#A: (_|_){
481-
// [structural cycle]
482-
a: (_|_){
483-
- // [structural cycle] b: structural cycle:
484-
- // ./in.cue:62:6
485-
+ // [structural cycle]
486-
}
487-
}
488-
#B: (_|_){
489-
- // [structural cycle] b: structural cycle:
490-
- // ./in.cue:62:6
491-
+ // [structural cycle]
492-
}
493-
}
494-
letCycleWithAnd: (struct){
495-
@@ -118,41 +112,34 @@
483+
@@ -118,41 +116,34 @@
496484
}
497485
b: (struct){
498486
}
@@ -554,7 +542,7 @@ diff old new
554542
}
555543
}
556544
embedCycle: (_|_){
557-
@@ -159,39 +146,45 @@
545+
@@ -159,39 +150,45 @@
558546
// [structural cycle]
559547
a: (_|_){
560548
// [structural cycle] embedCycle: structural cycle:
@@ -623,7 +611,7 @@ diff old new
623611
}
624612
}
625613
closeFail: (_|_){
626-
@@ -201,21 +194,22 @@
614+
@@ -201,21 +198,22 @@
627615
}
628616
x: (_|_){
629617
// [eval]

‎cue/testdata/cycle/inline.txtar

+24-24
Original file line numberDiff line numberDiff line change
@@ -153,14 +153,14 @@ inline: acrossFields: ok1: {
153153
}
154154
}
155155
-- out/evalalpha/stats --
156-
Leaks: 104
156+
Leaks: 92
157157
Freed: 0
158158
Reused: 0
159-
Allocs: 104
159+
Allocs: 92
160160
Retain: 0
161161

162-
Unifications: 100
163-
Conjuncts: 498
162+
Unifications: 88
163+
Conjuncts: 409
164164
Disjuncts: 0
165165
-- diff/-out/evalalpha/stats<==>+out/eval/stats --
166166
diff old new
@@ -172,17 +172,17 @@ diff old new
172172
-Reused: 136
173173
-Allocs: 252
174174
-Retain: 834
175-
+Leaks: 104
175+
+Leaks: 92
176176
+Freed: 0
177177
+Reused: 0
178-
+Allocs: 104
178+
+Allocs: 92
179179
+Retain: 0
180180

181181
-Unifications: 388
182182
-Conjuncts: 1307
183183
-Disjuncts: 707
184-
+Unifications: 100
185-
+Conjuncts: 498
184+
+Unifications: 88
185+
+Conjuncts: 409
186186
+Disjuncts: 0
187187
-- out/eval/stats --
188188
Leaks: 247
@@ -304,9 +304,9 @@ structural cycle:
304304
structural cycle:
305305
./x.cue:20:9
306306
in: structural cycle:
307-
./x.cue:38:17
307+
./x.cue:34:17
308308
in: structural cycle:
309-
./x.cue:54:17
309+
./x.cue:49:17
310310

311311
Result:
312312
(_|_){
@@ -372,15 +372,15 @@ Result:
372372
k00: (int){ 0 }
373373
k10: (_|_){
374374
// [structural cycle] in: structural cycle:
375-
// ./x.cue:38:17
375+
// ./x.cue:34:17
376376
}
377377
k20: (_|_){
378378
// [structural cycle] in: structural cycle:
379-
// ./x.cue:38:17
379+
// ./x.cue:34:17
380380
}
381381
k30: (_|_){
382382
// [structural cycle] in: structural cycle:
383-
// ./x.cue:38:17
383+
// ./x.cue:34:17
384384
}
385385
}
386386
ok1: (_|_){
@@ -392,15 +392,15 @@ Result:
392392
k00: (int){ 0 }
393393
k10: (_|_){
394394
// [structural cycle] in: structural cycle:
395-
// ./x.cue:54:17
395+
// ./x.cue:49:17
396396
}
397397
k20: (_|_){
398398
// [structural cycle] in: structural cycle:
399-
// ./x.cue:54:17
399+
// ./x.cue:49:17
400400
}
401401
k30: (_|_){
402402
// [structural cycle] in: structural cycle:
403-
// ./x.cue:54:17
403+
// ./x.cue:49:17
404404
}
405405
}
406406
}
@@ -421,9 +421,9 @@ diff old new
421421
./x.cue:20:9
422422
in: structural cycle:
423423
- ./x.cue:30:8
424-
+ ./x.cue:38:17
424+
+ ./x.cue:34:17
425425
+in: structural cycle:
426-
+ ./x.cue:54:17
426+
+ ./x.cue:49:17
427427

428428
Result:
429429
(_|_){
@@ -452,15 +452,15 @@ diff old new
452452
- }
453453
- }
454454
- ok1: (struct){
455-
+ // ./x.cue:38:17
455+
+ // ./x.cue:34:17
456456
+ }
457457
+ k20: (_|_){
458458
+ // [structural cycle] in: structural cycle:
459-
+ // ./x.cue:38:17
459+
+ // ./x.cue:34:17
460460
+ }
461461
+ k30: (_|_){
462462
+ // [structural cycle] in: structural cycle:
463-
+ // ./x.cue:38:17
463+
+ // ./x.cue:34:17
464464
+ }
465465
+ }
466466
+ ok1: (_|_){
@@ -475,15 +475,15 @@ diff old new
475475
- k30: (int){ 0 }
476476
+ k10: (_|_){
477477
+ // [structural cycle] in: structural cycle:
478-
+ // ./x.cue:54:17
478+
+ // ./x.cue:49:17
479479
+ }
480480
+ k20: (_|_){
481481
+ // [structural cycle] in: structural cycle:
482-
+ // ./x.cue:54:17
482+
+ // ./x.cue:49:17
483483
+ }
484484
+ k30: (_|_){
485485
+ // [structural cycle] in: structural cycle:
486-
+ // ./x.cue:54:17
486+
+ // ./x.cue:49:17
487487
+ }
488488
}
489489
}

‎cue/testdata/cycle/structural.txtar

+10-1
Original file line numberDiff line numberDiff line change
@@ -1329,7 +1329,7 @@ Result:
13291329
cheeseburger: (float){ 3.00 }
13301330
fries: (float){ 2.00 }
13311331
sprite: (float){ 1.00 }
1332-
total: (int){ 18 }
1332+
total: (int){ 12 }
13331333
}
13341334
}
13351335
listOptOK: (struct){
@@ -2206,6 +2206,15 @@ diff old new
22062206
}
22072207
}
22082208
fieldsSumInfinite: (struct){
2209+
@@ -753,7 +731,7 @@
2210+
cheeseburger: (float){ 3.00 }
2211+
fries: (float){ 2.00 }
2212+
sprite: (float){ 1.00 }
2213+
- total: (int){ 18 }
2214+
+ total: (int){ 12 }
2215+
}
2216+
}
2217+
listOptOK: (struct){
22092218
@@ -767,9 +745,7 @@
22102219
head: (int){ 3 }
22112220
tail: (struct){

‎internal/core/adt/cycle.go

+14
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,20 @@ func (n *nodeContext) hasAncestorV3(arc *Vertex) bool {
693693
return true
694694
}
695695

696+
// TODO(evalv3): replace the use of the old status mechanism.
697+
// the depth counters is an alternative mechanism to the status used in
698+
// the v2 evaluator. It is slightly more precise:
699+
// - it allows detecting reference cycles as well (state evaluating is
700+
// no longer used in v3)
701+
// - it can capture cycles across inline structs, which do not have
702+
// Parent set.
703+
// TODO: ensure that evalDepth is cleared when a node is finalized.
704+
if s := arc.state; s != nil && arc.status != finalized {
705+
if s.evalDepth > 0 && s.evalDepth < n.ctx.evalDepth {
706+
return true
707+
}
708+
}
709+
696710
// TODO: insert test conditions for Bloom filter that guarantee that all
697711
// parent nodes have been marked as "hot", in which case we can avoid this
698712
// traversal.

0 commit comments

Comments
 (0)
Please sign in to comment.