this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

internal/core/adt: avoid finalizing too early

unify pro-actively evaluates pending arcs. This
pro-active finalization could lead to tasks being
forcibly unblocked too early, leaving values to
function as "undefined".

We now only "require" pending arcs (yield) and
do not finalize. Note that if this results in blocks, this
will have the same effect as finalization.

This does uncover a situation where a value may
"yield" oustside of an underlying tasks. In this case,
we can simply "fall back" to finalization.

Added "related" issue, to show that this change does
not break that test.

Fixes #3919

Signed-off-by: Marcel van Lohuizen <mpvl@gmail.com>
Change-Id: Ifb6f6374edd9a5a93a43c83bfa002b3b4ee703fc
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1214950
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>
Unity-Result: CUE porcuepine <cue.porcuepine@gmail.com>

authored by

Marcel van Lohuizen and committed by
Daniel Martí
f87800db 47c9e99b

+177 -50
+8 -5
cue/testdata/eval/comprehensions.txtar
··· 271 271 // [eval] issue3691.structuralCycle.a.b.c: conflicting values string and {[string]:X} (mismatched types string and struct): 272 272 // ./issue3691.cue:14:15 273 273 // ./issue3691.cue:15:5 274 - b: (_|_){ 275 - // [cycle] cycle error 274 + b*: (_|_){// [e]if true { 275 + // c: 〈3;a〉 276 + // }[e] & 〈1;X〉 276 277 } 277 278 } 278 279 } ··· 307 308 // ./issue3691.cue:8:10 308 309 } 309 310 } 310 - @@ -145,13 +140,8 @@ 311 + @@ -145,13 +140,9 @@ 311 312 // [eval] issue3691.structuralCycle.a.b.c: conflicting values string and {[string]:X} (mismatched types string and struct): 312 313 // ./issue3691.cue:14:15 313 314 // ./issue3691.cue:15:5 314 315 - // ./issue3691.cue:17:3 315 316 - // ./issue3691.cue:18:10 316 - b: (_|_){ 317 + - b: (_|_){ 317 318 - // [structural cycle] 318 319 - c: (_|_){ 319 320 - // [structural cycle] issue3691.structuralCycle.a.b.c.b.c: structural cycle 320 321 - } 321 - + // [cycle] cycle error 322 + + b*: (_|_){// [e]if true { 323 + + // c: 〈3;a〉 324 + + // }[e] & 〈1;X〉 322 325 } 323 326 } 324 327 }
+161 -35
cue/testdata/eval/issue3919.txtar
··· 19 19 } 20 20 port: int | *30080 21 21 } 22 + -- secondary.cue -- 23 + related: { 24 + [string]: { 25 + if true { 26 + shared: all_total: foo.fooData.total 27 + } 28 + } 29 + foo: fooData: { 30 + total: tags: _hidden 31 + _hidden: extra: {} 32 + } 33 + #Tags: [string]: {} 34 + bar: { 35 + shared: { 36 + [string]: tags: #Tags 37 + bar_total: foo.fooData.total 38 + } 39 + } 40 + } 22 41 -- out/eval/stats -- 23 - Leaks: 0 24 - Freed: 13 25 - Reused: 5 42 + Leaks: 2 43 + Freed: 32 44 + Reused: 26 26 45 Allocs: 8 27 - Retain: 0 46 + Retain: 1 28 47 29 - Unifications: 9 30 - Conjuncts: 13 31 - Disjuncts: 13 48 + Unifications: 30 49 + Conjuncts: 51 50 + Disjuncts: 35 32 51 -- out/evalalpha -- 33 52 (struct){ 34 53 full: (struct){ 35 54 out: (struct){ 36 55 env: (struct){ 37 - PORT: (_|_){ 38 - // [incomplete] full.out.env.PORT: error in call to math.Abs: non-concrete value _: 39 - // ./in.cue:7:11 40 - } 56 + PORT: (int){ 30080 } 41 57 } 42 58 port: (int){ |(*(int){ 30080 }, (int){ int }) } 43 59 } 44 60 } 45 61 reduced: (struct){ 46 - a: (_|_){ 47 - // [incomplete] reduced.a: error in call to math.Abs: non-concrete value _: 48 - // ./in.cue:17:6 49 - } 62 + a: (int){ 30080 } 50 63 port: (int){ |(*(int){ 30080 }, (int){ int }) } 51 64 } 65 + related: (struct){ 66 + foo: (struct){ 67 + fooData: (struct){ 68 + total: (struct){ 69 + tags: ~(related.foo.fooData._hidden) 70 + } 71 + _hidden: (struct){ 72 + extra: (struct){ 73 + } 74 + } 75 + } 76 + shared: (struct){ 77 + all_total: ~(related.foo.fooData.total) 78 + } 79 + } 80 + #Tags: (#struct){ 81 + } 82 + bar: (struct){ 83 + shared: (struct){ 84 + bar_total: (struct){ 85 + tags: (#struct){ 86 + extra: (#struct){ 87 + } 88 + } 89 + } 90 + all_total: (struct){ 91 + tags: (#struct){ 92 + extra: (#struct){ 93 + } 94 + } 95 + } 96 + } 97 + } 98 + } 52 99 } 53 100 -- diff/-out/evalalpha<==>+out/eval -- 54 101 diff old new 55 102 --- old 56 103 +++ new 57 - @@ -2,13 +2,19 @@ 58 - full: (struct){ 59 - out: (struct){ 60 - env: (struct){ 61 - - PORT: (int){ 30080 } 62 - + PORT: (_|_){ 63 - + // [incomplete] full.out.env.PORT: error in call to math.Abs: non-concrete value _: 64 - + // ./in.cue:7:11 65 - + } 104 + @@ -15,10 +15,7 @@ 105 + foo: (struct){ 106 + fooData: (struct){ 107 + total: (struct){ 108 + - tags: (struct){ 109 + - extra: (struct){ 110 + - } 111 + - } 112 + + tags: ~(related.foo.fooData._hidden) 113 + } 114 + _hidden: (struct){ 115 + extra: (struct){ 116 + @@ -26,12 +23,7 @@ 117 + } 66 118 } 67 - port: (int){ |(*(int){ 30080 }, (int){ int }) } 119 + shared: (struct){ 120 + - all_total: (struct){ 121 + - tags: (struct){ 122 + - extra: (struct){ 123 + - } 124 + - } 125 + - } 126 + + all_total: ~(related.foo.fooData.total) 127 + } 68 128 } 69 - } 70 - reduced: (struct){ 71 - - a: (int){ 30080 } 72 - + a: (_|_){ 73 - + // [incomplete] reduced.a: error in call to math.Abs: non-concrete value _: 74 - + // ./in.cue:17:6 75 - + } 76 - port: (int){ |(*(int){ 30080 }, (int){ int }) } 77 - } 78 - } 129 + #Tags: (#struct){ 79 130 -- out/eval -- 80 131 (struct){ 81 132 full: (struct){ ··· 90 141 a: (int){ 30080 } 91 142 port: (int){ |(*(int){ 30080 }, (int){ int }) } 92 143 } 144 + related: (struct){ 145 + foo: (struct){ 146 + fooData: (struct){ 147 + total: (struct){ 148 + tags: (struct){ 149 + extra: (struct){ 150 + } 151 + } 152 + } 153 + _hidden: (struct){ 154 + extra: (struct){ 155 + } 156 + } 157 + } 158 + shared: (struct){ 159 + all_total: (struct){ 160 + tags: (struct){ 161 + extra: (struct){ 162 + } 163 + } 164 + } 165 + } 166 + } 167 + #Tags: (#struct){ 168 + } 169 + bar: (struct){ 170 + shared: (struct){ 171 + bar_total: (struct){ 172 + tags: (#struct){ 173 + extra: (#struct){ 174 + } 175 + } 176 + } 177 + all_total: (struct){ 178 + tags: (#struct){ 179 + extra: (#struct){ 180 + } 181 + } 182 + } 183 + } 184 + } 185 + } 93 186 } 94 187 -- out/compile -- 95 188 --- in.cue ··· 113 206 port: (int|*30080) 114 207 } 115 208 } 209 + --- secondary.cue 210 + { 211 + related: { 212 + [string]: { 213 + if true { 214 + shared: { 215 + all_total: 〈3;foo〉.fooData.total 216 + } 217 + } 218 + } 219 + foo: { 220 + fooData: { 221 + total: { 222 + tags: 〈1;_hidden〉 223 + } 224 + _hidden: { 225 + extra: {} 226 + } 227 + } 228 + } 229 + #Tags: { 230 + [string]: {} 231 + } 232 + bar: { 233 + shared: { 234 + [string]: { 235 + tags: 〈3;#Tags〉 236 + } 237 + bar_total: 〈2;foo〉.fooData.total 238 + } 239 + } 240 + } 241 + }
+6 -3
internal/core/adt/sched.go
··· 413 413 if s.meets(needs) { 414 414 return true 415 415 } 416 - c.current().waitFor(s, needs) 417 - s.yield() 418 - panic("unreachable") 416 + // This can happen in some cases. We "promote" to finalization if this 417 + // was not triggered by a task. 418 + if t := c.current(); t != nil { 419 + t.waitFor(s, needs) 420 + s.yield() 421 + } 419 422 420 423 case finalize: 421 424 // remainder of function
+2 -7
internal/core/adt/unify.go
··· 214 214 if n.node.ArcType == ArcPending { 215 215 // forcefully do an early recursive evaluation to decide the state 216 216 // of the arc. See https://cuelang.org/issue/3621. 217 - n.process(nodeOnlyNeeds, attemptOnly) 218 - if n.node.ArcType == ArcPending { 219 - for _, a := range n.node.Arcs { 220 - a.unify(c, needs, attemptOnly, checkTypos) 221 - } 222 - } 223 - n.completePending(mode) 217 + n.process(pendingKnown, yield) 218 + n.completePending(yield) 224 219 } 225 220 226 221 n.process(nodeOnlyNeeds, mode)