this repo has no description
0
fork

Configure Feed

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

internal/core: implement let as fields

This makes it easier to get upCounts aligned, as they will follow
the same paradigm as fields. It also allows debug information to be
shown as to where lets are added in the tree.

Mote, however, that lets do not always behave as fields: even if the
same let is added into the same struct multiple times, the various
instance should be treated as unique fields and should not be unified.
For this purpose, the old cache is still used.

Fixes #1828

Signed-off-by: Marcel van Lohuizen <mpvl@gmail.com>
Change-Id: Ifa459a2f0f16b2cf57c72c45a1f7b906326527b7
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/543362
Reviewed-by: Roger Peppe <rogpeppe@gmail.com>
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>

+852 -223
+6 -2
cue/testdata/basicrewrite/aliases/aliases.txtar
··· 14 14 { 15 15 t0: { 16 16 _a: _ 17 - _out: 〈0;let _b〉 17 + let _b#1 = 〈0;_a〉 18 + _out: 〈0;let _b#1〉 18 19 } 19 20 t1: { 20 - _a: 〈0;let b〉 21 + _a: 〈0;let b#2〉 22 + let b#2 = 〈0;d〉 21 23 d: 3 22 24 } 23 25 } ··· 25 27 (struct){ 26 28 t0: (struct){ 27 29 _a: (_){ _ } 30 + let _b#1 = (_){ _ } 28 31 _out: (_){ _ } 29 32 } 30 33 t1: (struct){ 31 34 _a: (int){ 3 } 35 + let b#2 = (int){ 3 } 32 36 d: (int){ 3 } 33 37 } 34 38 }
+12 -1
cue/testdata/builtins/closed.txtar
··· 81 81 a: (#struct){ 82 82 b: (bool){ true } 83 83 } 84 + let X#1 = (#struct){ 85 + b: (bool){ true } 86 + } 84 87 uint: (#struct){ 85 88 a: (#struct){ 86 89 b: (bool){ true } ··· 88 91 } 89 92 }, (#struct){ 90 93 a: (#struct){ 94 + b: (bool){ true } 95 + } 96 + let X#1 = (#struct){ 91 97 b: (bool){ true } 92 98 } 93 99 string: (#struct){ ··· 102 108 a: (#struct){ 103 109 b: (bool){ true } 104 110 } 111 + let X#1 = 〈0;a〉 // multi 105 112 uint: (#struct){ 106 113 a: (#struct){ 107 114 b: (bool){ true } ··· 111 118 a: (#struct){ 112 119 b: (bool){ true } 113 120 } 121 + let X#1 = 〈0;a〉 // multi 114 122 string: (#struct){ 115 123 a: (#struct){ 116 124 b: (bool){ true } ··· 121 129 a: (#struct){ 122 130 b: (bool){ true } 123 131 } 132 + let X#1 = 〈0;a〉 // multi 124 133 uint: (#struct){ 125 134 a: (#struct){ 126 135 b: (bool){ true } ··· 130 139 a: (#struct){ 131 140 b: (bool){ true } 132 141 } 142 + let X#1 = 〈0;a〉 // multi 133 143 string: (#struct){ 134 144 a: (#struct){ 135 145 b: (bool){ true } ··· 191 201 a: { 192 202 b: true 193 203 } 204 + let X#1 = 〈0;a〉 194 205 (close({ 195 206 uint: { 196 207 a: { 197 - b: 〈3;let X〉.b 208 + b: 〈3;let X#1〉.b 198 209 } 199 210 } 200 211 })|close({
+1
cue/testdata/compile/erralias.txtar
··· 22 22 ./in.cue:10:16 23 23 --- in.cue 24 24 { 25 + let X#1 = {} 25 26 ["foo"]: 3 26 27 a: _|_(reference "Y" not found) 27 28 "\(〈0;b〉)": 3
+2 -1
cue/testdata/compile/labels.txtar
··· 51 51 dis1: ("dev"|"prd") 52 52 dis2: (*"dev"|"prd") 53 53 con1: string 54 + let con2#1 = string 54 55 ok0: { 55 56 [string]: string 56 57 } ··· 61 62 [〈1;con1〉]: string 62 63 } 63 64 ok3: { 64 - [〈1;let con2〉]: string 65 + [〈1;let con2#1〉]: string 65 66 } 66 67 ok4: { 67 68 ["foo"]: string
+40 -7
cue/testdata/compile/let.txtar
··· 62 62 --- in.cue 63 63 { 64 64 a: { 65 - b: 〈0;let X〉 65 + let X#1 = 〈0;let Y#2〉 66 + let Y#2 = 〈0;c〉 67 + b: 〈0;let X#1〉 66 68 c: 5 67 69 } 68 70 b: { 69 - b: 〈0;let X〉 71 + let X#3 = 〈0;let Y#4〉 72 + let Y#4 = 〈0;let X#3〉 73 + b: 〈0;let X#3〉 70 74 c: 5 71 75 } 72 76 fieldOffset: { 73 77 a: { 74 78 p1: { 75 - x: 〈0;let X〉 79 + let X#5 = { 80 + value: 〈1;let Y#6〉 81 + } 82 + let Y#6 = 2 83 + x: 〈0;let X#5〉 76 84 } 77 85 p2: { 78 - x: 〈0;let X〉 86 + x: 〈0;let X#8〉 87 + let Y#7 = 2 88 + let X#8 = { 89 + value: 〈1;let Y#7〉 90 + } 79 91 } 80 92 } 81 93 b: { 82 94 p1: { 83 - x: 〈0;let X〉 95 + let X#9 = { 96 + x: { 97 + y: 〈2;let Y#A〉 98 + } 99 + } 100 + let Y#A = 2 101 + x: 〈0;let X#9〉 84 102 } 85 103 p2: { 86 - x: 〈0;let X〉 104 + x: 〈0;let X#C〉 105 + let Y#B = 2 106 + let X#C = { 107 + x: { 108 + y: 〈2;let Y#B〉 109 + } 110 + } 87 111 } 88 112 } 89 113 } 90 114 issue767: { 91 115 #Foo: { 92 - out: 〈0;let _#volmnts〉 116 + let _#bar#D = { 117 + value: "" 118 + } 119 + let _#volmnts#E = { 120 + x: 〈1;let _#baz#F〉.value 121 + } 122 + let _#baz#F = { 123 + 〈1;let _#bar#D〉 124 + } 125 + out: 〈0;let _#volmnts#E〉 93 126 } 94 127 } 95 128 }
+13 -2
cue/testdata/compile/scope.txtar
··· 68 68 b: 〈1;-〉 69 69 } 70 70 } 71 - f: 〈0;let B〉 71 + let B#1 = { 72 + open: int 73 + } 74 + f: 〈0;let B#1〉 72 75 schema: { 73 - next: 〈1;let _schema_1〉 76 + next: 〈1;let _schema_1#2〉 74 77 } 78 + let _schema_1#2 = 〈0;schema〉 75 79 } 76 80 -- out/eval -- 77 81 Errors: ··· 96 100 c: (string){ "foo" } 97 101 d: (struct){ 98 102 } 103 + let B#1 = (struct){ 104 + open: (int){ int } 105 + } 99 106 f: (struct){ 100 107 open: (int){ int } 101 108 } ··· 104 111 next: (_|_){ 105 112 // [structural cycle] schema.next: structural cycle 106 113 } 114 + } 115 + let _schema_1#2 = (_|_){ 116 + // [structural cycle] _schema_1: structural cycle: 117 + // ./in.cue:32:8 107 118 } 108 119 }
+36 -2
cue/testdata/comprehensions/issue837.txtar
··· 155 155 // [eval] 156 156 description: (_|_){ 157 157 // [eval] 158 + let dep#1 = (#struct){ 159 + service: (#struct){ 160 + ref: (#struct){ 161 + kind: (string){ "service" } 162 + } 163 + description: (_|_){ 164 + // [incomplete] #DoDeploy.deployment.description.dep.service.description: undefined field: service: 165 + // ./in.cue:5:28 166 + } 167 + } 168 + hsize: (#struct){ 169 + } 170 + } 158 171 service: (_|_){ 159 172 // [eval] _params.hsize.$_instances: conflicting values 1 and {$_instances:(>=0|*1)} (mismatched types int and struct): 160 173 // ./in.cue:29:20 ··· 182 195 // [eval] 183 196 description: (_|_){ 184 197 // [eval] 198 + let configed#2 = (_|_){ 199 + // [eval] _params.hsize.$_instances: conflicting values 1 and {$_instances:(>=0|*1)} (mismatched types int and struct): 200 + // ./in.cue:29:20 201 + // ./in.cue:35:13 202 + // ./in.cue:55:12 203 + // ./in.cue:56:22 204 + // _params.hsize.$_instances: conflicting values >=0 and {$_instances:(>=0|*1)} (mismatched types number and struct): 205 + // ./in.cue:29:20 206 + // ./in.cue:35:13 207 + // ./in.cue:55:12 208 + // ./in.cue:56:15 209 + // _params.hsize.$_instances: 2 errors in empty disjunction:: 210 + // ./in.cue:33:20 211 + } 185 212 role: (_|_){ 186 213 // [eval] _params.hsize.$_instances: conflicting values 1 and {$_instances:(>=0|*1)} (mismatched types int and struct): 187 214 // ./in.cue:29:20 ··· 270 297 } 271 298 deployment: { 272 299 description: { 300 + let dep#1 = 〈2;_params〉.manifest.description 273 301 service: (〈3;#Configure〉 & { 274 302 _params: { 275 - hsize: 〈2;let dep〉.hsize 303 + hsize: 〈2;let dep#1〉.hsize 276 304 } 277 305 }).service 278 306 } ··· 286 314 } 287 315 service: { 288 316 description: { 289 - role: 〈0;let configed〉.role 317 + let configed#2 = (〈3;#RelabelService〉 & { 318 + _params: { 319 + hsize: 〈4;_params〉.hsize 320 + } 321 + role: "admin" 322 + }).out 323 + role: 〈0;let configed#2〉.role 290 324 } 291 325 } 292 326 }
+4 -2
cue/testdata/comprehensions/nested.txtar
··· 68 68 name: (string){ "metrics" } 69 69 port: (int){ 9100 } 70 70 protocol: (string){ "TCP" } 71 + let Port#1 = (int){ 9100 } 71 72 targetPort: (int){ |(*(int){ 9100 }, (int){ int }) } 72 73 } 73 74 } ··· 213 214 spec: { 214 215 ports: [ 215 216 for _, c in 〈5;v〉.spec.template.spec.containers for _, p in 〈0;c〉.ports if 〈0;p〉._export { 216 - port: (*〈0;let Port〉|int) 217 - targetPort: (*〈0;let Port〉|int) 217 + let Port#1 = 〈1;p〉.containerPort 218 + port: (*〈0;let Port#1〉|int) 219 + targetPort: (*〈0;let Port#1〉|int) 218 220 }, 219 221 ] 220 222 }
+6 -1
cue/testdata/cycle/evaluate.txtar
··· 115 115 // [structural cycle] letCycle.0: structural cycle: 116 116 // ./in.cue:34:9 117 117 } 118 + let X#1 = (_|_){ 119 + // [structural cycle] letCycle.0: structural cycle: 120 + // ./in.cue:34:9 121 + } 118 122 c: (_|_){ 119 123 // [structural cycle] letCycle.0: structural cycle: 120 124 // ./in.cue:34:9 ··· 273 277 { 274 278 letCycle: { 275 279 b: 〈0;c〉 276 - c: 〈0;let X〉 280 + let X#1 = 〈0;b〉 281 + c: 〈0;let X#1〉 277 282 } 278 283 listCycle: { 279 284 a: 〈0;b〉
+86 -1
cue/testdata/cycle/issue990.txtar
··· 106 106 [string]: _ 107 107 } 108 108 for rn, rd in 〈0;#p〉.d.r if (〈0;rd〉.a.k == "complex") { 109 - for sn, sd in 〈0;let subs〉.dict { 109 + let subs#1 = (〈3;#sub〉 & { 110 + #p: 〈2;rd〉.a 111 + }) 112 + for sn, sd in 〈0;let subs#1〉.dict { 110 113 dict: { 111 114 "\(〈4;rn〉)_\(〈2;sn〉)": 〈2;sd〉 112 115 } ··· 401 404 } 402 405 } 403 406 } 407 + } 408 + } 409 + } 410 + } 411 + } 412 + } 413 + } 414 + } 415 + let subs#1 = (#struct){ 416 + dict: (#struct){ 417 + r1: (#struct){ 418 + a: (#struct){ 419 + k: (string){ "simple" } 420 + d: (#struct){ 421 + n: (string){ "c1" } 422 + } 423 + } 424 + } 425 + r2_r1: (#struct){ 426 + a: (#struct){ 427 + k: (string){ "simple" } 428 + d: (#struct){ 429 + n: (string){ "c1" } 430 + } 431 + } 432 + } 433 + } 434 + #p: (#struct){ 435 + k: (string){ "complex" } 436 + d: (#struct){ 437 + n: (string){ "s2" } 438 + r: (#struct){ 439 + r1: (#struct){ 440 + a: (#struct){ 441 + k: (string){ "simple" } 442 + d: (#struct){ 443 + n: (string){ "c1" } 444 + } 445 + } 446 + } 447 + r2: (#struct){ 448 + a: (#struct){ 449 + k: (string){ "complex" } 450 + d: (#struct){ 451 + n: (string){ "s3" } 452 + r: (#struct){ 453 + r1: (#struct){ 454 + a: (#struct){ 455 + k: (string){ "simple" } 456 + d: (#struct){ 457 + n: (string){ "c1" } 458 + } 459 + } 460 + } 461 + } 462 + } 463 + } 464 + } 465 + } 466 + } 467 + } 468 + let subs#1 = (#struct){ 469 + dict: (#struct){ 470 + r1: (#struct){ 471 + a: (#struct){ 472 + k: (string){ "simple" } 473 + d: (#struct){ 474 + n: (string){ "c1" } 475 + } 476 + } 477 + } 478 + } 479 + #p: (#struct){ 480 + k: (string){ "complex" } 481 + d: (#struct){ 482 + n: (string){ "s3" } 483 + r: (#struct){ 484 + r1: (#struct){ 485 + a: (#struct){ 486 + k: (string){ "simple" } 487 + d: (#struct){ 488 + n: (string){ "c1" } 404 489 } 405 490 } 406 491 }
+6 -1
cue/testdata/cycle/structural.txtar
··· 1293 1293 // [structural cycle] withLetFail.schema.next: structural cycle 1294 1294 } 1295 1295 } 1296 + let _schema_1#1 = (_|_){ 1297 + // [structural cycle] withLetFail._schema_1: structural cycle: 1298 + // ./in.cue:355:17 1299 + } 1296 1300 } 1297 1301 listOptOK: (struct){ 1298 1302 list: (struct){ ··· 2227 2231 } 2228 2232 withLetFail: { 2229 2233 schema: { 2230 - next: 〈1;let _schema_1〉 2234 + next: 〈1;let _schema_1#1〉 2231 2235 } 2236 + let _schema_1#1 = 〈0;schema〉 2232 2237 } 2233 2238 listOptOK: { 2234 2239 list: {
+88 -2
cue/testdata/eval/let.txtar
··· 24 24 a: T 25 25 b: F 26 26 } 27 + issue1828: { 28 + volumes: L3 29 + 30 + let L3 = { 31 + for v2 in [ for v1 in L2 {} ] {} 32 + } 33 + 34 + let L2 = L1 35 + let L1 = [] 36 + } 37 + ignoreErrorInLet: { 38 + let X = 1 & 2 39 + disjunction: *X | 3 40 + } 27 41 -- out/eval -- 28 42 (struct){ 43 + let A#1 = (int){ 9 } 44 + let B#2 = (int){ 18 } 45 + let C#3 = (int){ 36 } 46 + let D#4 = (int){ 72 } 47 + let E#5 = (int){ 144 } 48 + let F#6 = (int){ 288 } 29 49 b: (struct){ 50 + let G#7 = (int){ 576 } 51 + let H#8 = (int){ 1152 } 52 + let I#9 = (int){ 2304 } 53 + let J#A = (int){ 4608 } 54 + let K#B = (int){ 9216 } 55 + let L#C = (int){ 18432 } 56 + let M#D = (int){ 36864 } 57 + let N#E = (int){ 73728 } 58 + let O#F = (int){ 147456 } 59 + let P#10 = (int){ 294912 } 60 + let Q#11 = (int){ 589824 } 61 + let R#12 = (int){ 1179648 } 62 + let S#13 = (int){ 2359296 } 63 + let T#14 = (int){ 4718592 } 30 64 a: (int){ 4718592 } 31 65 b: (int){ 288 } 32 66 } 67 + issue1828: (struct){ 68 + volumes: (struct){ 69 + } 70 + let L3#15 = (struct){ 71 + } 72 + let L2#16 = (#list){ 73 + } 74 + let L1#17 = (#list){ 75 + } 76 + } 77 + ignoreErrorInLet: (struct){ 78 + let X#18 = (_|_){ 79 + // [eval] ignoreErrorInLet.X: conflicting values 2 and 1: 80 + // ./in.cue:37:10 81 + // ./in.cue:37:14 82 + } 83 + disjunction: (int){ 3 } 84 + } 33 85 } 34 86 -- out/compile -- 35 87 --- in.cue 36 88 { 89 + let A#1 = (3 * 3) 90 + let B#2 = (〈0;let A#1〉 + 〈0;let A#1〉) 91 + let C#3 = (〈0;let B#2〉 + 〈0;let B#2〉) 92 + let D#4 = (〈0;let C#3〉 + 〈0;let C#3〉) 93 + let E#5 = (〈0;let D#4〉 + 〈0;let D#4〉) 94 + let F#6 = (〈0;let E#5〉 + 〈0;let E#5〉) 37 95 b: { 38 - a: 〈0;let T〉 39 - b: 〈1;let F〉 96 + let G#7 = (〈1;let F#6〉 + 〈1;let F#6〉) 97 + let H#8 = (〈0;let G#7〉 + 〈0;let G#7〉) 98 + let I#9 = (〈0;let H#8〉 + 〈0;let H#8〉) 99 + let J#A = (〈0;let I#9〉 + 〈0;let I#9〉) 100 + let K#B = (〈0;let J#A〉 + 〈0;let J#A〉) 101 + let L#C = (〈0;let K#B〉 + 〈0;let K#B〉) 102 + let M#D = (〈0;let L#C〉 + 〈0;let L#C〉) 103 + let N#E = (〈0;let M#D〉 + 〈0;let M#D〉) 104 + let O#F = (〈0;let N#E〉 + 〈0;let N#E〉) 105 + let P#10 = (〈0;let O#F〉 + 〈0;let O#F〉) 106 + let Q#11 = (〈0;let P#10〉 + 〈0;let P#10〉) 107 + let R#12 = (〈0;let Q#11〉 + 〈0;let Q#11〉) 108 + let S#13 = (〈0;let R#12〉 + 〈0;let R#12〉) 109 + let T#14 = (〈0;let S#13〉 + 〈0;let S#13〉) 110 + a: 〈0;let T#14〉 111 + b: 〈1;let F#6〉 112 + } 113 + issue1828: { 114 + volumes: 〈0;let L3#15〉 115 + let L3#15 = { 116 + for _, v2 in [ 117 + for _, v1 in 〈2;let L2#16〉 {}, 118 + ] {} 119 + } 120 + let L2#16 = 〈0;let L1#17〉 121 + let L1#17 = [] 122 + } 123 + ignoreErrorInLet: { 124 + let X#18 = (1 & 2) 125 + disjunction: (*〈0;let X#18〉|3) 40 126 } 41 127 }
+47 -2
cue/testdata/eval/letjoin.txtar
··· 49 49 x: (struct){ 50 50 a: (int){ int } 51 51 y: (struct){ 52 + let X#1 = (struct){ 53 + b: (int){ int } 54 + c: (int){ 1 } 55 + } 52 56 v: (int){ 1 } 53 57 } 54 58 } 55 59 x1: (struct){ 56 60 a: (int){ 1 } 57 61 y: (struct){ 62 + let X#1 = (struct){ 63 + b: (int){ 1 } 64 + c: (int){ 1 } 65 + } 58 66 v: (int){ 1 } 59 67 } 60 68 } 61 69 x2: (struct){ 62 70 a: (int){ 2 } 63 71 y: (struct){ 72 + let X#1 = (struct){ 73 + b: (int){ 2 } 74 + c: (int){ 1 } 75 + } 64 76 v: (int){ 1 } 65 77 } 66 78 } 67 79 xy: (struct){ 80 + let X#1 = { 81 + b: 〈2;a〉 82 + c: 1 83 + } // multi 68 84 v: (int){ 1 } 69 85 } 70 86 } ··· 73 89 a: (struct){ 74 90 } 75 91 y: (struct){ 92 + let X#2 = (struct){ 93 + b: (struct){ 94 + } 95 + c: (int){ 1 } 96 + } 76 97 v: (int){ 1 } 77 98 } 78 99 } ··· 81 102 q: (int){ 1 } 82 103 } 83 104 y: (struct){ 105 + let X#2 = (struct){ 106 + b: (struct){ 107 + q: (int){ 1 } 108 + } 109 + c: (int){ 1 } 110 + } 84 111 v: (int){ 1 } 85 112 } 86 113 } ··· 89 116 r: (int){ 2 } 90 117 } 91 118 y: (struct){ 119 + let X#2 = (struct){ 120 + b: (struct){ 121 + r: (int){ 2 } 122 + } 123 + c: (int){ 1 } 124 + } 92 125 v: (int){ 1 } 93 126 } 94 127 } ··· 98 131 r: (int){ 2 } 99 132 } 100 133 y: (struct){ 134 + let X#2 = { 135 + b: 〈2;a〉 136 + c: 1 137 + } // multi 101 138 v: (int){ 1 } 102 139 } 103 140 } ··· 110 147 x: { 111 148 a: int 112 149 y: { 113 - v: 〈0;let X〉.c 150 + let X#1 = { 151 + b: 〈2;a〉 152 + c: 1 153 + } 154 + v: 〈0;let X#1〉.c 114 155 } 115 156 } 116 157 x1: 〈0;x〉 ··· 127 168 x: { 128 169 a: {} 129 170 y: { 130 - v: 〈0;let X〉.c 171 + let X#2 = { 172 + b: 〈2;a〉 173 + c: 1 174 + } 175 + v: 〈0;let X#2〉.c 131 176 } 132 177 } 133 178 x1: 〈0;x〉
+17 -3
cue/testdata/fulleval/049_alias_reuse_in_nested_scope.txtar
··· 67 67 -- out/eval -- 68 68 (struct){ 69 69 #Foo: (#struct){ 70 + let X#1 = (_|_){ 71 + // [incomplete] empty list in call to or: 72 + // ./in.cue:2:10 73 + } 70 74 connection: (#struct){ 71 75 } 72 76 } 73 77 #A: (#struct){ 74 78 foo: (string){ "key" } 79 + let X#2 = (string){ "key" } 75 80 a: (#struct){ 76 81 foo: (#struct){ 77 82 } ··· 79 84 } 80 85 #B: (#struct){ 81 86 foo: (string){ string } 87 + let X#3 = (string){ string } 82 88 a: (#struct){ 83 89 foo: (#struct){ 84 90 } ··· 86 92 } 87 93 b: (#struct){ 88 94 foo: (string){ "key" } 95 + let X#3 = (string){ "key" } 89 96 a: (#struct){ 90 97 foo: (#struct){ 91 98 } ··· 96 103 --- in.cue 97 104 { 98 105 #Foo: { 106 + let X#1 = or([ 107 + for k, _ in {} { 108 + 〈1;k〉 109 + }, 110 + ]) 99 111 connection: { 100 - [〈1;let X〉]: 〈1;let X〉 112 + [〈1;let X#1〉]: 〈1;let X#1〉 101 113 } 102 114 } 103 115 #A: { 104 116 foo: "key" 117 + let X#2 = 〈0;foo〉 105 118 a: { 106 119 foo: { 107 - [〈2;let X〉]: 〈2;let X〉 120 + [〈2;let X#2〉]: 〈2;let X#2〉 108 121 } 109 122 } 110 123 } 111 124 #B: { 112 125 foo: string 126 + let X#3 = 〈0;foo〉 113 127 a: { 114 128 foo: { 115 - [〈2;let X〉]: 〈2;let X〉 129 + [〈2;let X#3〉]: 〈2;let X#3〉 116 130 } 117 131 } 118 132 }
+66 -13
cue/testdata/references/let.txtar
··· 83 83 1 84 84 }, 85 85 ] 86 - a1: ((100 * 〈0;let A1〉[0]) + 〈0;let A1〉[0]) 86 + let A1#1 = 〈0;a1list〉 87 + a1: ((100 * 〈0;let A1#1〉[0]) + 〈0;let A1#1〉[0]) 87 88 a2list: [ 88 89 { 89 90 2 90 91 }, 91 92 ] 93 + let A2#2 = 〈0;a2list〉 92 94 a2: { 93 - b: ((100 * 〈1;let A2〉[0]) + 〈1;let A2〉[0]) 95 + b: ((100 * 〈1;let A2#2〉[0]) + 〈1;let A2#2〉[0]) 94 96 } 95 97 a3list: [ 96 98 { 97 99 3 98 100 }, 99 101 ] 102 + let A3#3 = 〈0;a3list〉 100 103 a3: { 101 104 b: { 102 - c: ((100 * 〈2;let A3〉[0]) + 〈2;let A3〉[0]) 105 + c: ((100 * 〈2;let A3#3〉[0]) + 〈2;let A3#3〉[0]) 103 106 } 104 107 } 105 108 a4list: [ ··· 107 110 4 108 111 }, 109 112 ] 113 + let A4#4 = 〈0;a4list〉 110 114 a4: [ 111 - for _, x in 〈1;let A4〉 { 115 + for _, x in 〈1;let A4#4〉 { 112 116 v: 404 113 117 }, 114 118 ] ··· 117 121 5 118 122 }, 119 123 ] 124 + let A5#5 = 〈0;a5list〉 120 125 a5: { 121 126 b: [ 122 - for _, x in 〈2;let A5〉 { 127 + for _, x in 〈2;let A5#5〉 { 123 128 v: 505 124 129 }, 125 130 ] ··· 129 134 6 130 135 }, 131 136 ] 137 + let A6#6 = 〈0;a6list〉 132 138 a6: { 133 139 b: { 134 140 c: [ 135 - for _, x in 〈3;let A6〉 { 141 + for _, x in 〈3;let A6#6〉 { 136 142 v: 606 137 143 }, 138 144 ] ··· 143 149 7 144 150 }, 145 151 ] 152 + let A7#7 = 〈0;a7list〉 146 153 a7: { 147 - for _, x in 〈1;let A7〉 { 154 + for _, x in 〈1;let A7#7〉 { 148 155 v: 707 149 156 } 150 157 } ··· 153 160 8 154 161 }, 155 162 ] 163 + let A8#8 = 〈0;a8list〉 156 164 a8: { 157 165 b: { 158 - for _, x in 〈2;let A8〉 { 166 + for _, x in 〈2;let A8#8〉 { 159 167 v: 808 160 168 } 161 169 } ··· 165 173 9 166 174 }, 167 175 ] 176 + let A9#9 = 〈0;a9list〉 168 177 a9: { 169 178 b: { 170 179 c: { 171 - for _, x in 〈3;let A9〉 { 180 + for _, x in 〈3;let A9#9〉 { 172 181 v: 909 173 182 } 174 183 } ··· 187 196 max: 〈import;list〉.Max(〈1;input〉) 188 197 } 189 198 bar: { 190 - min: 〈0;let mn〉 191 - max: 〈0;let mx〉 199 + let mn#A = 〈1;last〉.min 200 + let mx#B = 〈import;list〉.max 201 + min: 〈0;let mn#A〉 202 + max: 〈0;let mx#B〉 192 203 } 193 204 x: { 194 205 if (〈import;list〉.max < 0) {} ··· 200 211 "a", 201 212 "b", 202 213 ] 203 - 〈0;let List〉[(len(〈0;let List〉) - 1)] 214 + let List#C = 〈0;#a〉 215 + 〈0;let List#C〉[(len(〈0;let List#C〉) - 1)] 204 216 } 205 217 b: { 206 - 〈0;let List〉[(len(〈0;let List〉) - 1)] 218 + let List#D = 〈0;#a〉 219 + 〈0;let List#D〉[(len(〈0;let List#D〉) - 1)] 207 220 #a: [ 208 221 "a", 209 222 "b", ··· 216 229 a1list: (#list){ 217 230 0: (int){ 1 } 218 231 } 232 + let A1#1 = (#list){ 233 + 0: (int){ 1 } 234 + } 219 235 a1: (int){ 101 } 220 236 a2list: (#list){ 237 + 0: (int){ 2 } 238 + } 239 + let A2#2 = (#list){ 221 240 0: (int){ 2 } 222 241 } 223 242 a2: (struct){ ··· 226 245 a3list: (#list){ 227 246 0: (int){ 3 } 228 247 } 248 + let A3#3 = (#list){ 249 + 0: (int){ 3 } 250 + } 229 251 a3: (struct){ 230 252 b: (struct){ 231 253 c: (int){ 303 } ··· 234 256 a4list: (#list){ 235 257 0: (int){ 4 } 236 258 } 259 + let A4#4 = (#list){ 260 + 0: (int){ 4 } 261 + } 237 262 a4: (#list){ 238 263 0: (struct){ 239 264 v: (int){ 404 } 240 265 } 241 266 } 242 267 a5list: (#list){ 268 + 0: (int){ 5 } 269 + } 270 + let A5#5 = (#list){ 243 271 0: (int){ 5 } 244 272 } 245 273 a5: (struct){ ··· 252 280 a6list: (#list){ 253 281 0: (int){ 6 } 254 282 } 283 + let A6#6 = (#list){ 284 + 0: (int){ 6 } 285 + } 255 286 a6: (struct){ 256 287 b: (struct){ 257 288 c: (#list){ ··· 262 293 } 263 294 } 264 295 a7list: (#list){ 296 + 0: (int){ 7 } 297 + } 298 + let A7#7 = (#list){ 265 299 0: (int){ 7 } 266 300 } 267 301 a7: (struct){ ··· 270 304 a8list: (#list){ 271 305 0: (int){ 8 } 272 306 } 307 + let A8#8 = (#list){ 308 + 0: (int){ 8 } 309 + } 273 310 a8: (struct){ 274 311 b: (struct){ 275 312 v: (int){ 808 } 276 313 } 277 314 } 278 315 a9list: (#list){ 316 + 0: (int){ 9 } 317 + } 318 + let A9#9 = (#list){ 279 319 0: (int){ 9 } 280 320 } 281 321 a9: (struct){ ··· 298 338 max: (int){ 5 } 299 339 } 300 340 bar: (struct){ 341 + let mn#A = (int){ 1 } 342 + let mx#B = (_|_){ 343 + // [incomplete] incompleteLet.bar.mx: undefined field: max: 344 + // ./in.cue:54:17 345 + } 301 346 min: (int){ 1 } 302 347 max: (_|_){ 303 348 // [incomplete] incompleteLet.bar.max: undefined field: max: ··· 316 361 0: (string){ "a" } 317 362 1: (string){ "b" } 318 363 } 364 + let List#C = (#list){ 365 + 0: (string){ "a" } 366 + 1: (string){ "b" } 367 + } 319 368 } 320 369 b: (string){ 321 370 "b" 371 + let List#D = (#list){ 372 + 0: (string){ "a" } 373 + 1: (string){ "b" } 374 + } 322 375 #a: (#list){ 323 376 0: (string){ "a" } 324 377 1: (string){ "b" }
+28 -3
cue/testdata/references/letcycle.txtar
··· 56 56 { 57 57 cycles: { 58 58 a: { 59 - out: 〈0;let A〉 59 + let A#1 = { 60 + c: 〈1;let B#2〉 61 + } 62 + let B#2 = 〈0;let A#1〉 63 + out: 〈0;let A#1〉 60 64 } 61 65 b: { 62 - out: 〈0;let A〉 66 + let A#3 = { 67 + c: 〈1;let B#4〉 68 + } 69 + let B#4 = { 70 + 〈1;let A#3〉.c 71 + } 72 + out: 〈0;let A#3〉 63 73 } 64 74 issue1042: { 65 75 #FullAdder: { ··· 79 89 out: ([ 80 90 bool, 81 91 ] * 16) 92 + let fulladders#5 = [ 93 + for _, i in 〈import;list〉.Range(0, 4, 1) { 94 + (〈4;#FullAdder〉 & { 95 + a: 〈4;a〉[〈2;i〉] 96 + b: 〈4;b〉[〈2;i〉] 97 + c: 〈4;let carries#6〉[〈2;i〉] 98 + }) 99 + }, 100 + ] 101 + let carries#6 = [ 102 + false, 103 + for _, i in 〈import;list〉.Range(0, 4, 1) { 104 + 〈3;let fulladders#5〉[〈1;i〉].carry 105 + }, 106 + ] 82 107 out: [ 83 108 for _, i in 〈import;list〉.Range(0, 4, 1) { 84 - 〈3;let fulladders〉[〈1;i〉].sum 109 + 〈3;let fulladders#5〉[〈1;i〉].sum 85 110 }, 86 111 ] 87 112 }
+10 -1
cue/testdata/resolve/035_excluded_embedding_from_closing.txtar
··· 51 51 d: int 52 52 } 53 53 } 54 - b: 〈0;let B〉 54 + let B#1 = { 55 + open: int 56 + } 57 + b: 〈0;let B#1〉 55 58 } 56 59 V: (〈0;#S〉 & { 57 60 c: { ··· 85 88 a: (#struct){ 86 89 c: (int){ int } 87 90 } 91 + let B#1 = (#struct){ 92 + open: (int){ int } 93 + } 88 94 b: (#struct){ 89 95 open: (int){ int } 90 96 } ··· 104 110 } 105 111 a: (#struct){ 106 112 c: (int){ int } 113 + } 114 + let B#1 = (#struct){ 115 + open: (int){ int } 107 116 } 108 117 b: (_|_){ 109 118 // [eval]
+3
cue/types.go
··· 1402 1402 1403 1403 k := 0 1404 1404 for _, f := range features { 1405 + if f.IsLet() { 1406 + continue 1407 + } 1405 1408 if f.IsDef() && (o.omitDefinitions || o.concrete) { 1406 1409 continue 1407 1410 }
+3
internal/core/adt/adt.go
··· 236 236 func (x *Field) expr() Expr { return x.Value } 237 237 func (*OptionalField) declNode() {} 238 238 func (x *OptionalField) expr() Expr { return x.Value } 239 + func (*LetField) declNode() {} 240 + func (x *LetField) expr() Expr { return x.Value } 239 241 func (*BulkOptionalField) declNode() {} 240 242 func (x *BulkOptionalField) expr() Expr { return x.Value } 241 243 func (*DynamicField) declNode() {} ··· 370 372 func (*DisjunctionExpr) node() {} 371 373 func (*Field) node() {} 372 374 func (*OptionalField) node() {} 375 + func (*LetField) node() {} 373 376 func (*BulkOptionalField) node() {} 374 377 func (*DynamicField) node() {} 375 378 func (*Ellipsis) node() {}
+8 -2
internal/core/adt/composite.go
··· 91 91 // TODO(perf): make the following public fields a shareable struct as it 92 92 // mostly is going to be the same for child nodes. 93 93 94 + // TODO: This can probably move into the nodeContext, making it a map from 95 + // conjunct to Value. 94 96 cache map[Expr]Value 95 97 } 96 98 ··· 103 105 104 106 type ID int32 105 107 106 - // evalCached is used to look up let expressions. Caching let expressions 107 - // prevents a possible combinatorial explosion. 108 + // evalCached is used to look up dynamic field pattern constraint expressions. 108 109 func (e *Environment) evalCached(c *OpContext, x Expr) Value { 109 110 if v, ok := x.(Value); ok { 110 111 return v ··· 162 163 // case, for instance, if it is a node in a definition or if one of the 163 164 // conjuncts, or ancestor conjuncts, is a definition. 164 165 Closed bool 166 + 167 + // MultiLet indicates whether multiple let fields were added from 168 + // different sources. If true, a LetReference must be resolved using 169 + // the per-Environment value cache. 170 + MultiLet bool 165 171 166 172 // arcType indicates the level of optionality of this arc. 167 173 arcType arcType
+15
internal/core/adt/context.go
··· 474 474 return arc, err 475 475 } 476 476 477 + // Lookup looks up r in env without further resolving the value. 478 + func (c *OpContext) Lookup(env *Environment, r Resolver) (*Vertex, *Bottom) { 479 + s := c.PushState(env, r.Source()) 480 + 481 + arc := r.resolve(c, Partial) 482 + 483 + err := c.PopState(s) 484 + 485 + if arc != nil { 486 + arc = arc.Indirect() 487 + } 488 + 489 + return arc, err 490 + } 491 + 477 492 // Validate calls validates value for the given validator. 478 493 // 479 494 // TODO(errors): return boolean instead: only the caller has enough information
+10 -3
internal/core/adt/eval.go
··· 708 708 continue 709 709 } 710 710 711 - if err, _ := a.BaseValue.(*Bottom); err != nil { 711 + if err, _ := a.BaseValue.(*Bottom); err != nil && !a.Label.IsLet() { 712 712 n.node.AddChildError(err) 713 713 } 714 714 ··· 1808 1808 1809 1809 for _, d := range s.Decls { 1810 1810 switch x := d.(type) { 1811 - case *Field: 1811 + case *Field, *LetField: 1812 1812 // handle in next iteration. 1813 1813 1814 1814 case *DynamicField: ··· 1854 1854 n.aStructID = closeInfo 1855 1855 } 1856 1856 n.insertField(x.Label, MakeConjunct(childEnv, x, closeInfo)) 1857 + 1858 + case *LetField: 1859 + n.insertField(x.Label, MakeConjunct(childEnv, x, closeInfo)) 1857 1860 } 1858 1861 } 1859 1862 } ··· 1871 1874 // disjunctions. 1872 1875 func (n *nodeContext) insertField(f Feature, x Conjunct) *Vertex { 1873 1876 ctx := n.ctx 1874 - arc, _ := n.node.GetArc(ctx, f, arcMember) 1877 + arc, isNew := n.node.GetArc(ctx, f, arcMember) 1878 + if f.IsLet() && !isNew { 1879 + arc.MultiLet = true 1880 + return arc 1881 + } 1875 1882 arc.addConjunct(x) 1876 1883 1877 1884 switch {
+1 -2
internal/core/adt/eval_test.go
··· 49 49 test.ToDo = nil 50 50 } 51 51 52 - r := runtime.New() 53 - 54 52 test.Run(t, func(t *cuetxtar.Test) { 55 53 a := t.Instance() 54 + r := runtime.New() 56 55 57 56 v, err := r.Build(nil, a) 58 57 if err != nil {
+55 -15
internal/core/adt/expr.go
··· 112 112 o.Fields[p].Optional = append(o.Fields[p].Optional, x) 113 113 o.types |= HasField 114 114 115 + case *LetField: 116 + if o.fieldIndex(x.Label) >= 0 { 117 + panic("duplicate let identifier") 118 + } 119 + o.Fields = append(o.Fields, FieldInfo{Label: x.Label}) 120 + 115 121 case *DynamicField: 116 122 o.Dynamic = append(o.Dynamic, x) 117 123 o.types |= HasDynamic ··· 213 219 } 214 220 215 221 func (x *OptionalField) Source() ast.Node { 222 + if x.Src == nil { 223 + return nil 224 + } 225 + return x.Src 226 + } 227 + 228 + // A LetField represents a field that is only visible in the local scope. 229 + // 230 + // let X = expr 231 + type LetField struct { 232 + Src *ast.LetClause 233 + Label Feature 234 + Value Expr 235 + } 236 + 237 + func (x *LetField) Source() ast.Node { 216 238 if x.Src == nil { 217 239 return nil 218 240 } ··· 866 888 return x.Src 867 889 } 868 890 869 - func (x *LetReference) resolve(c *OpContext, state VertexStatus) *Vertex { 870 - e := c.Env(x.UpCount) 871 - label := e.Vertex.Label 872 - if x.X == nil { 873 - panic("nil expression") 891 + func (x *LetReference) resolve(ctx *OpContext, state VertexStatus) *Vertex { 892 + e := ctx.Env(x.UpCount) 893 + n := e.Vertex 894 + 895 + // No need to Unify n, as Let references can only result from evaluating 896 + // an experssion within n, in which case evaluation must already have 897 + // started. 898 + if n.status < Evaluating { 899 + panic("unexpected node state < Evaluating") 874 900 } 875 - // Anonymous arc. 876 - return &Vertex{ 877 - Parent: e.Vertex, 878 - Label: label, 879 - Conjuncts: []Conjunct{{e, x.X, c.ci}}, 901 + 902 + arc := ctx.lookup(n, pos(x), x.Label, state) 903 + if arc == nil { 904 + return nil 880 905 } 881 - } 882 906 883 - func (x *LetReference) evaluate(c *OpContext) Value { 884 - e := c.Env(x.UpCount) 907 + if !arc.MultiLet { 908 + return arc 909 + } 885 910 886 911 // Not caching let expressions may lead to exponential behavior. 887 - return e.evalCached(c, x.X) 912 + // The expr uses the expression of a Let field, which can never be used in 913 + // any other context. 914 + expr := arc.Conjuncts[0].Expr() 915 + v, ok := e.cache[expr] 916 + if !ok { 917 + if e.cache == nil { 918 + e.cache = map[Expr]Value{} 919 + } 920 + v = &Vertex{ 921 + Parent: n, 922 + Label: x.Label, 923 + Conjuncts: []Conjunct{{e, expr, ctx.ci}}, 924 + } 925 + e.cache[expr] = v 926 + } 927 + return v.(*Vertex) 888 928 } 889 929 890 930 // A SelectorExpr looks up a fixed field in an expression. ··· 1755 1795 } 1756 1796 } 1757 1797 1758 - // An LetClause represents a let clause in a comprehension. 1798 + // A LetClause represents a let clause in a comprehension. 1759 1799 // 1760 1800 // let x = y 1761 1801 type LetClause struct {
+1
internal/core/adt/expr_test.go
··· 48 48 &Interpolation{}, 49 49 &LabelReference{}, 50 50 &LetClause{}, 51 + &LetField{}, 51 52 &LetReference{}, 52 53 &ListLit{}, 53 54 &ListMarker{},
+37 -1
internal/core/adt/feature.go
··· 60 60 61 61 // ToString returns a string s for index such that ToIndex(s) == index. 62 62 IndexToString(index int64) string 63 + 64 + // NextUniqueID returns a new unique identifier. 65 + NextUniqueID() uint64 63 66 } 64 67 65 68 // SelectorString reports the shortest string representation of f when used as a ··· 90 93 // is not an identifier label. 91 94 func (f Feature) IdentString(index StringIndexer) string { 92 95 s := index.IndexToString(f.safeIndex()) 93 - if f.IsHidden() { 96 + if f.IsHidden() || f.IsLet() { 94 97 if p := strings.IndexByte(s, '\x00'); p >= 0 { 95 98 s = s[:p] 96 99 } ··· 117 120 if !f.IsString() { 118 121 panic("not a string label") 119 122 } 123 + x := f.safeIndex() 124 + return index.IndexToString(x) 125 + } 126 + 127 + // RawString reports the underlying string value of f without interpretation. 128 + func (f Feature) RawString(index StringIndexer) string { 120 129 x := f.safeIndex() 121 130 return index.IndexToString(x) 122 131 } ··· 191 200 return f 192 201 } 193 202 203 + // MakeLetLabel creates a label for the given let identifier s. 204 + // 205 + // A let declaration is always logically unique within its scope and will never 206 + // unify with a let field of another struct. This is enforced by ensuring that 207 + // the let identifier is unique across an entire configuration. This, in turn, 208 + // is done by adding a unique number to each let identifier. 209 + func MakeLetLabel(r StringIndexer, s string) Feature { 210 + id := r.NextUniqueID() 211 + s = fmt.Sprintf("%s\x00%X", s, id) 212 + i := r.StringToIndex(s) 213 + f, err := MakeLabel(nil, i, LetLabel) 214 + if err != nil { 215 + panic("out of free string slots") 216 + } 217 + return f 218 + } 219 + 194 220 // MakeIntLabel creates an integer label. 195 221 func MakeIntLabel(t FeatureType, i int64) Feature { 196 222 f, err := MakeLabel(nil, i, t) ··· 294 320 DefinitionLabel 295 321 HiddenLabel 296 322 HiddenDefinitionLabel 323 + LetLabel 297 324 ) 298 325 299 326 const ( ··· 308 335 309 336 func (f FeatureType) IsHidden() bool { 310 337 return f == HiddenLabel || f == HiddenDefinitionLabel 338 + } 339 + 340 + func (f FeatureType) IsLet() bool { 341 + return f == LetLabel 311 342 } 312 343 313 344 // IsValid reports whether f is a valid label. ··· 338 369 // _ or #_). 339 370 func (f Feature) IsHidden() bool { 340 371 return f.Typ().IsHidden() 372 + } 373 + 374 + // IsLet reports whether this label is a let field (like `let X = value`). 375 + func (f Feature) IsLet() bool { 376 + return f.Typ().IsLet() 341 377 } 342 378 343 379 // Index reports the abstract index associated with f.
+28 -16
internal/core/compile/compile.go
··· 153 153 srcExpr ast.Expr 154 154 expr adt.Expr 155 155 source ast.Node 156 + feature adt.Feature // For let declarations 156 157 used bool 157 158 } 158 159 ··· 202 203 203 204 switch { 204 205 case entry.label != nil: 206 + // TODO: allow cyclic references in let expressions once these can be 207 + // encoded as a ValueReference. 205 208 if entry.srcExpr == nil { 206 209 entry.expr = c.errf(id, "cyclic references in let clause or alias") 207 210 break ··· 344 347 upCount += c.upCountOffset 345 348 for p := c.Scope; p != nil; p = p.Parent() { 346 349 for _, a := range p.Vertex().Arcs { 347 - if a.Label == label { 350 + switch { 351 + case a.Label.IsLet() && a.Label.IdentString(c.index) == n.Name: 352 + label = a.Label 353 + case a.Label == label: 348 354 return &adt.FieldReference{ 349 355 Src: n, 350 356 UpCount: upCount, ··· 442 448 if entry.expr == nil { 443 449 panic("unreachable") 444 450 } 451 + label = entry.feature 445 452 446 453 // let x = y 447 454 return &adt.LetReference{ 448 455 Src: n, 449 456 UpCount: upCount, 450 457 Label: label, 451 - X: entry.expr, 458 + X: entry.expr, // TODO: remove usage 452 459 } 453 460 454 461 // TODO: handle new-style aliases ··· 529 536 label: (*letScope)(x), 530 537 srcExpr: x.Expr, 531 538 source: x, 539 + feature: adt.MakeLetLabel(c.index, x.Ident.Name), 532 540 } 533 541 c.insertAlias(x.Ident, a) 534 542 ··· 634 642 } 635 643 } 636 644 637 - // Handled in addLetDecl. 638 645 case *ast.LetClause: 646 + m := c.stack[len(c.stack)-1].aliases 647 + entry := m[x.Ident.Name] 648 + 649 + // A reference to the let should, in principle, be interpreted as a 650 + // value reference, not field reference: 651 + // - this is syntactically consistent for the use of = 652 + // - this is semantically the only valid interpretation 653 + // In practice this amounts to the same thing, as let expressions cannot 654 + // be addressed from outside their scope. But it will matter once 655 + // expressions may refer to a let from within the let. 656 + value := c.labeledExpr(x, (*letScope)(x), x.Expr) 657 + 658 + return &adt.LetField{ 659 + Src: x, 660 + Label: entry.feature, 661 + Value: value, 662 + } 663 + 639 664 // case: *ast.Alias: // TODO(value alias) 640 665 641 666 case *ast.CommentGroup: ··· 664 689 665 690 func (c *compiler) addLetDecl(d ast.Decl) { 666 691 switch x := d.(type) { 667 - // An alias reference will have an expression that is looked up in the 668 - // environment cash. 669 - case *ast.LetClause: 670 - // Cache the parsed expression. Creating a unique expression for each 671 - // reference allows the computation to be shared given that we don't 672 - // have fields for expressions. This, in turn, prevents exponential 673 - // blowup in x2: x1+x1, x3: x2+x2, ... patterns. 674 - expr := c.labeledExpr(nil, (*letScope)(x), x.Expr) 675 - c.updateAlias(x.Ident, expr) 676 - 677 692 case *ast.Field: 678 693 lab := x.Label 679 694 if a, ok := lab.(*ast.Alias); ok { ··· 799 814 } 800 815 801 816 func (c *compiler) labeledExprAt(k int, f ast.Decl, lab labeler, expr ast.Expr) adt.Expr { 802 - if c.stack[k].field != nil { 803 - panic("expected nil field") 804 - } 805 817 saved := c.stack[k] 806 818 807 819 c.stack[k].label = lab
+1 -2
internal/core/compile/compile_test.go
··· 44 44 test.ToDo = nil 45 45 } 46 46 47 - r := runtime.New() 48 - 49 47 test.Run(t, func(t *cuetxtar.Test) { 48 + r := runtime.New() 50 49 // TODO: use high-level API. 51 50 52 51 a := t.Instance()
+22 -3
internal/core/debug/compact.go
··· 50 50 if i > 0 { 51 51 w.string(",") 52 52 } 53 - w.label(a.Label) 54 - w.string(":") 55 - w.node(a) 53 + if a.Label.IsLet() { 54 + w.string("let ") 55 + w.label(a.Label) 56 + w.string("=") 57 + if c := a.Conjuncts[0]; a.MultiLet { 58 + w.node(c.Expr()) 59 + w.string(" // multi") 60 + continue 61 + } 62 + w.node(a) 63 + } else { 64 + w.label(a.Label) 65 + w.string(":") 66 + w.node(a) 67 + } 56 68 } 57 69 w.string("}") 58 70 ··· 106 118 s := w.labelString(x.Label) 107 119 w.string(s) 108 120 w.string("?:") 121 + w.node(x.Value) 122 + 123 + case *adt.LetField: 124 + w.string("let ") 125 + s := w.labelString(x.Label) 126 + w.string(s) 127 + w.string("=") 109 128 w.node(x.Value) 110 129 111 130 case *adt.BulkOptionalField:
+33 -6
internal/core/debug/debug.go
··· 94 94 95 95 // TODO: fold into label once :: is no longer supported. 96 96 func (w *printer) labelString(f adt.Feature) string { 97 - if f.IsHidden() { 97 + switch { 98 + case f.IsHidden(): 98 99 ident := f.IdentString(w.index) 99 100 if pkgName := f.PkgID(w.index); pkgName != "_" { 100 101 ident = fmt.Sprintf("%s(%s)", ident, pkgName) 101 102 } 102 103 return ident 104 + 105 + case f.IsLet(): 106 + ident := f.RawString(w.index) 107 + ident = strings.Replace(ident, "\x00", "#", 1) 108 + return ident 109 + 110 + default: 111 + return f.SelectorString(w.index) 103 112 } 104 - return f.SelectorString(w.index) 105 113 } 106 114 107 115 func (w *printer) shortError(errs errors.Error) { ··· 214 222 215 223 for _, a := range x.Arcs { 216 224 w.string("\n") 217 - w.label(a.Label) 218 - w.string(": ") 219 - w.node(a) 225 + if a.Label.IsLet() { 226 + w.string("let ") 227 + w.label(a.Label) 228 + w.string(" = ") 229 + if c := a.Conjuncts[0]; a.MultiLet { 230 + w.node(c.Expr()) 231 + w.string(" // multi") 232 + continue 233 + } 234 + w.node(a) 235 + } else { 236 + w.label(a.Label) 237 + w.string(": ") 238 + w.node(a) 239 + } 220 240 } 221 241 222 242 if x.BaseValue == nil { ··· 287 307 w.string(":") 288 308 } 289 309 w.string(" ") 310 + w.node(x.Value) 311 + 312 + case *adt.LetField: 313 + w.string("let ") 314 + s := w.labelString(x.Label) 315 + w.string(s) 316 + w.string(" = ") 290 317 w.node(x.Value) 291 318 292 319 case *adt.BulkOptionalField: ··· 391 418 w.string(openTuple) 392 419 w.string(strconv.Itoa(int(x.UpCount))) 393 420 w.string(";let ") 394 - w.ident(x.Label) 421 + w.label(x.Label) 395 422 w.string(closeTuple) 396 423 397 424 case *adt.SelectorExpr:
+9 -10
internal/core/dep/dep.go
··· 218 218 219 219 // markResolve resolves dependencies. 220 220 func (c *visitor) markResolver(env *adt.Environment, r adt.Resolver) { 221 - switch x := r.(type) { 222 - case nil: 223 - case *adt.LetReference: 224 - saved := c.ctxt.PushState(env, nil) 225 - env := c.ctxt.Env(x.UpCount) 226 - c.markExpr(env, x.X) 227 - c.ctxt.PopState(saved) 228 - return 229 - } 230 - 231 221 // Note: it is okay to pass an empty CloseInfo{} here as we assume that 232 222 // all nodes are finalized already and we need neither closedness nor cycle 233 223 // checks. 234 224 if ref, _ := c.ctxt.Resolve(adt.MakeConjunct(env, r, adt.CloseInfo{}), r); ref != nil { 225 + if ref.Label.IsLet() { 226 + x := r.(*adt.LetReference) 227 + saved := c.ctxt.PushState(env, nil) 228 + env := c.ctxt.Env(x.UpCount) 229 + c.markExpr(env, ref.Conjuncts[0].Expr()) 230 + c.ctxt.PopState(saved) 231 + return 232 + } 233 + 235 234 if ref != c.node && ref != empty { 236 235 d := Dependency{ 237 236 Node: ref,
+3
internal/core/dep/mixed.go
··· 85 85 case *adt.BulkOptionalField: 86 86 m.markExpr(x.Value) 87 87 88 + case *adt.LetField: 89 + m.markExpr(x.Value) 90 + 88 91 case *adt.DynamicField: 89 92 m.markExpr(x.Value) 90 93
+9
internal/core/export/adt.go
··· 68 68 } 69 69 } 70 70 decl := e.decl(env, d) 71 + // decl may be nil if it represents a let. Lets are added later, and 72 + // only when they are still used. 73 + if decl == nil { 74 + continue 75 + } 71 76 72 77 if a != nil { 73 78 if f, ok := decl.(*ast.Field); ok { ··· 431 436 432 437 // extractDocs(nil) 433 438 return f 439 + 440 + case *adt.LetField: 441 + // Handled elsewhere 442 + return nil 434 443 435 444 case *adt.BulkOptionalField: 436 445 e.setDocs(x)
+13 -1
internal/core/export/export.go
··· 425 425 426 426 switch { 427 427 case let == nil: 428 - return e.expr(env, x.X) 428 + ref, _ := e.ctx.Lookup(env, x) 429 + if ref == nil { 430 + // This can happen if x.X does not resolve to a valid value. At this 431 + // point we will not get a valid configuration. 432 + 433 + // TODO: get rid of the use of x.X. 434 + // str := x.Label.IdentString(e.ctx) 435 + // ident := ast.NewIdent(str) 436 + // return ident 437 + 438 + return e.expr(env, x.X) 439 + } 440 + return e.expr(env, ref.Conjuncts[0].Expr()) 429 441 430 442 case let.Expr == nil: 431 443 label := e.uniqueLetIdent(x.Label, x.X)
+2 -29
internal/core/export/export_test.go
··· 269 269 270 270 in := ` 271 271 -- in.cue -- 272 - package test 273 - 274 - // // Foo 275 - // a: [X=string]: [Y=string]: { 276 - // name: X+Y 277 - // } 278 - 279 - // [Y=string]: [X=string]: name: {Y+X} 280 - // { 281 - // name: X.other + Y 282 - // other: string 283 - // } 284 - 285 - // c: [X=string]: X 286 - 287 - // #pkg1: Object 288 - 289 - // "Hello \(#pkg1)!" 290 - 291 - 292 - // Object: "World" 293 - 294 - // // A Foo fooses stuff. 295 - // foos are instances of Foo. 296 - // foos: [string]: {} 297 - 298 - // // // My first little foo. 299 - // foos: MyFoo: {} 300 272 ` 301 273 302 274 archive := txtar.Parse([]byte(in)) ··· 308 280 // x := a[0].Files[0] 309 281 // astutil.Sanitize(x) 310 282 311 - r := runtime.New() 283 + ctx := cuecontext.New() 284 + r := (*runtime.Runtime)(ctx) 312 285 v, errs := compile.Files(nil, r, "", a[0].Files...) 313 286 if errs != nil { 314 287 t.Fatal(errs)
+7
internal/core/export/expr.go
··· 229 229 } 230 230 231 231 for _, f := range fields { 232 + if f.IsLet() { 233 + continue 234 + } 232 235 field := e.fields[f] 233 236 c := field.conjuncts 234 237 ··· 375 378 case *adt.OptionalField: 376 379 // TODO: mark optional here. 377 380 label = f.Label 381 + case *adt.LetField: 382 + continue 378 383 case *adt.Ellipsis: 379 384 e.hasEllipsis = true 380 385 continue ··· 506 511 return ok 507 512 } 508 513 } 514 + 515 + case *adt.LetField: 509 516 510 517 case adt.Expr: 511 518
+1
internal/core/export/self_test.go
··· 83 83 } 84 84 85 85 func buildFile(t *testing.T, r *cue.Context, b *build.Instance) cue.Value { 86 + t.Helper() 86 87 v := r.BuildInstance(b) 87 88 if err := v.Err(); err != nil { 88 89 t.Fatal(errors.Details(err, nil))
+1
internal/core/export/testdata/main/alias.txtar
··· 170 170 was known to compile and is known to be correct. 171 171 172 172 [issue1308] 173 + [issue1308 _xA] 173 174 [issue1308 sub] 174 175 [issue1308 sub 0] 175 176 [issue1308 sub 0 _A]
+95 -68
internal/core/export/testdata/main/let.txtar
··· 1 1 # Issue #590 2 2 3 3 -- in.cue -- 4 - let X = 1 + 1 4 + let X = 1 + 1 5 5 #Foo: X 6 6 -- x.cue -- 7 7 x: string ··· 143 143 } 144 144 }] 145 145 for cfg in cfgs { 146 - let filepath_1 = "kind-\(cfg.name)" 146 + let filepath = "kind-\(cfg.name)" 147 147 files: { 148 - "\(filepath_1)": { 148 + "\(filepath)": { 149 149 patches: cfg 150 150 } 151 151 } ··· 155 155 for cfg in [{ 156 156 a: "one" 157 157 }] { 158 - let filepath = "kind-\(cfg.name)" 159 - "\(filepath)": { 158 + let filepath_1 = "kind-\(cfg.name)" 159 + "\(filepath_1)": { 160 160 patches: cfg 161 161 } 162 162 } ··· 174 174 required: 1 175 175 } 176 176 direct: { 177 + let Args = _args 178 + a: Args.required 179 + } 180 + embed1: { 177 181 let Args_1 = _args 178 182 a: Args_1.required 179 183 } 180 - embed1: { 184 + embed2: { 181 185 let Args_2 = _args 182 186 a: Args_2.required 183 187 } 184 - embed2: { 188 + list: { 185 189 let Args_3 = _args 186 - a: Args_3.required 190 + a: [Args_3.required] 187 191 } 188 - list: { 192 + listStruct: { 189 193 let Args_4 = _args 190 - a: [Args_4.required] 191 - } 192 - listStruct: { 193 - let Args_8 = _args 194 194 a: [{ 195 - a: Args_8.required 195 + a: Args_4.required 196 196 }] 197 197 } 198 198 listEmbed: { 199 - let Args_32 = _args 200 - a: [Args_32.required] 199 + let Args_8 = _args 200 + a: [Args_8.required] 201 201 } 202 202 } 203 203 x: "foo" ··· 229 229 } 230 230 d: { 231 231 let A_4 = run.a 232 - let A_9 = run2.a 232 + let A_32 = run2.a 233 233 x: "a \(A_4) z" 234 - x2: "a \(A_9) z" 234 + x2: "a \(A_32) z" 235 235 run: { 236 236 a: string 237 237 } ··· 242 242 } 243 243 unresolvedDisjunction: { 244 244 #TypePrimitive: { 245 - let Args = _args 245 + let Args_9 = _args 246 246 { 247 247 "*": {} 248 248 } | { 249 249 bool: #TypeBool & { 250 250 _args: { 251 - required: Args.required 251 + required: Args_9.required 252 252 } 253 253 } 254 254 } ··· 271 271 -- out/doc -- 272 272 [] 273 273 [comprehension] 274 + [comprehension filepath] 275 + [X] 274 276 [#Foo] 275 277 [complete] 278 + [complete A] 276 279 [complete x] 277 280 [complete run] 278 281 [complete run a] ··· 282 285 [incomplete a run] 283 286 [incomplete a run a] 284 287 [incomplete b] 288 + [incomplete b A] 285 289 [incomplete b x] 286 290 [incomplete b run] 287 291 [incomplete b run a] 288 292 [incomplete c] 293 + [incomplete c A] 289 294 [incomplete c x] 290 295 [incomplete c run] 291 296 [incomplete c run a] 297 + [incomplete c A] 292 298 [incomplete c x2] 293 299 [incomplete c run2] 294 300 [incomplete c run2 a] 295 301 [incomplete d] 302 + [incomplete d A] 296 303 [incomplete d x] 297 304 [incomplete d run] 298 305 [incomplete d run a] 306 + [incomplete d A] 299 307 [incomplete d x2] 300 308 [incomplete d run2] 301 309 [incomplete d run2 a] ··· 303 311 [unresolvedDisjunction #TypePrimitive] 304 312 [unresolvedDisjunction #TypePrimitive _args] 305 313 [unresolvedDisjunction #TypePrimitive _args required] 314 + [unresolvedDisjunction #TypePrimitive Args] 315 + [unresolvedDisjunction #TypePrimitive Args required] 306 316 [unresolvedDisjunction #TypePrimitive "*"] 307 317 [unresolvedDisjunction #TypeBool] 308 318 [unresolvedDisjunction #TypeBool default] 309 319 [unresolvedDisjunction #TypeBool _args] 310 320 [unresolvedDisjunction #TypeBool _args required] 321 + [unresolvedDisjunction #TypeBool Args] 322 + [unresolvedDisjunction #TypeBool Args required] 311 323 [files] 312 324 [cfgs] 313 325 [cfgs 0] ··· 320 332 [scoped _args] 321 333 [scoped _args required] 322 334 [scoped direct] 335 + [scoped direct Args] 336 + [scoped direct Args required] 323 337 [scoped direct a] 324 338 [scoped embed1] 339 + [scoped embed1 Args] 340 + [scoped embed1 Args required] 325 341 [scoped embed1 a] 326 342 [scoped embed2] 343 + [scoped embed2 Args] 344 + [scoped embed2 Args required] 327 345 [scoped embed2 a] 328 346 [scoped list] 347 + [scoped list Args] 348 + [scoped list Args required] 329 349 [scoped list a] 330 350 [scoped list a 0] 331 351 [scoped listStruct] 352 + [scoped listStruct Args] 353 + [scoped listStruct Args required] 332 354 [scoped listStruct a] 333 355 [scoped listStruct a 0] 334 356 [scoped listStruct a 0 a] 335 357 [scoped listEmbed] 358 + [scoped listEmbed Args] 359 + [scoped listEmbed Args required] 336 360 [scoped listEmbed a] 337 361 [scoped listEmbed a 0] 338 362 [x] 363 + [Y] 339 364 [y] 365 + [Y] 366 + [filepath] 340 367 -- out/value -- 341 368 == Simplified 342 369 { ··· 401 428 } 402 429 } 403 430 b: { 404 - let A_1 = run.a 405 - x: "a \(A_1) z" 431 + let A = run.a 432 + x: "a \(A) z" 406 433 run: { 407 434 a: string 408 435 } 409 436 } 410 437 c: { 411 - let A_2 = run.a 412 - let A_3 = run2.a 413 - x: "a \(A_2) z" 414 - x2: "a \(A_3) z" 438 + let A_1 = run.a 439 + let A_2 = run2.a 440 + x: "a \(A_1) z" 441 + x2: "a \(A_2) z" 415 442 run: { 416 443 a: string 417 444 } ··· 420 447 } 421 448 } 422 449 d: { 423 - let A_4 = run.a 424 - let A_8 = run2.a 425 - x: "a \(A_4) z" 426 - x2: "a \(A_8) z" 450 + let A_3 = run.a 451 + let A_4 = run2.a 452 + x: "a \(A_3) z" 453 + x2: "a \(A_4) z" 427 454 run: { 428 455 a: string 429 456 } ··· 502 529 } 503 530 } 504 531 b: { 505 - let A_1 = run.a 506 - x: "a \(A_1) z" 532 + let A = run.a 533 + x: "a \(A) z" 507 534 run: { 508 535 a: string 509 536 } 510 537 } 511 538 c: { 512 - let A_2 = run.a 513 - let A_3 = run2.a 514 - x: "a \(A_2) z" 515 - x2: "a \(A_3) z" 539 + let A_1 = run.a 540 + let A_2 = run2.a 541 + x: "a \(A_1) z" 542 + x2: "a \(A_2) z" 516 543 run: { 517 544 a: string 518 545 } ··· 521 548 } 522 549 } 523 550 d: { 524 - let A_4 = run.a 525 - let A_8 = run2.a 526 - x: "a \(A_4) z" 527 - x2: "a \(A_8) z" 551 + let A_3 = run.a 552 + let A_4 = run2.a 553 + x: "a \(A_3) z" 554 + x2: "a \(A_4) z" 528 555 run: { 529 556 a: string 530 557 } ··· 541 568 "*": {} 542 569 } 543 570 #TypeBool: { 544 - let Args_1 = _args 571 + let Args = _args 545 572 _args: { 546 573 required: bool 547 574 } 548 - if !Args_1.required { 575 + if !Args.required { 549 576 // `default` sets the default value. 550 577 default: bool | null 551 578 } ··· 555 582 } 556 583 == Final 557 584 { 558 - comprehension: _|_ // invalid interpolation: invalid interpolation: comprehension: undefined field: name 585 + comprehension: _|_ // invalid interpolation: cycle error 559 586 complete: { 560 587 x: "a foo z" 561 588 run: { ··· 571 598 name: "two" 572 599 } 573 600 }] 574 - files: _|_ // invalid interpolation: invalid interpolation: files: undefined field: name (and 3 more errors) 601 + files: _|_ // invalid interpolation: cycle error (and 3 more errors) 575 602 scoped: { 576 603 direct: { 577 604 a: 1 ··· 699 726 } 700 727 } 701 728 b: { 702 - let A_1 = run.a 703 - x: "a \(A_1) z" 729 + let A = run.a 730 + x: "a \(A) z" 704 731 run: { 705 732 a: string 706 733 } 707 734 } 708 735 c: { 709 - let A_2 = run.a 710 - let A_3 = run2.a 711 - x: "a \(A_2) z" 712 - x2: "a \(A_3) z" 736 + let A_1 = run.a 737 + let A_2 = run2.a 738 + x: "a \(A_1) z" 739 + x2: "a \(A_2) z" 713 740 run: { 714 741 a: string 715 742 } ··· 718 745 } 719 746 } 720 747 d: { 721 - let A_4 = run.a 722 - let A_8 = run2.a 723 - x: "a \(A_4) z" 724 - x2: "a \(A_8) z" 748 + let A_3 = run.a 749 + let A_4 = run2.a 750 + x: "a \(A_3) z" 751 + x2: "a \(A_4) z" 725 752 run: { 726 753 a: string 727 754 } ··· 738 765 "*": {} 739 766 } 740 767 #TypeBool: { 741 - let Args_1 = _args 768 + let Args = _args 742 769 _args: { 743 770 required: bool 744 771 } 745 - if !Args_1.required { 772 + if !Args.required { 746 773 // `default` sets the default value. 747 774 default: bool | null 748 775 } ··· 814 841 } 815 842 } 816 843 b: { 817 - let A_1 = run.a 818 - x: "a \(A_1) z" 844 + let A = run.a 845 + x: "a \(A) z" 819 846 run: { 820 847 a: string 821 848 } 822 849 } 823 850 c: { 824 - let A_2 = run.a 825 - let A_3 = run2.a 826 - x: "a \(A_2) z" 827 - x2: "a \(A_3) z" 851 + let A_1 = run.a 852 + let A_2 = run2.a 853 + x: "a \(A_1) z" 854 + x2: "a \(A_2) z" 828 855 run: { 829 856 a: string 830 857 } ··· 833 860 } 834 861 } 835 862 d: { 836 - let A_4 = run.a 837 - let A_8 = run2.a 838 - x: "a \(A_4) z" 839 - x2: "a \(A_8) z" 863 + let A_3 = run.a 864 + let A_4 = run2.a 865 + x: "a \(A_3) z" 866 + x2: "a \(A_4) z" 840 867 run: { 841 868 a: string 842 869 } ··· 850 877 "*": {} 851 878 } 852 879 #TypeBool: { 853 - let Args_1 = _args 880 + let Args = _args 854 881 _args: { 855 882 required: bool 856 883 } 857 - if !Args_1.required { 884 + if !Args.required { 858 885 default: bool | null 859 886 } 860 887 }
+11
internal/core/runtime/imports.go
··· 65 65 importsByPath map[string]*adt.Vertex 66 66 importsByBuild map[*build.Instance]*adt.Vertex 67 67 68 + nextUniqueID uint64 69 + 68 70 // These are initialized during Go package initialization time and do not 69 71 // need to be guarded. 70 72 builtinPaths map[string]PackageFunc // Full path 71 73 builtinShort map[string]string // Commandline shorthand 72 74 73 75 typeCache sync.Map // map[reflect.Type]evaluated 76 + } 77 + 78 + func (i *index) getNextUniqueID() uint64 { 79 + // TODO: use atomic increment instead. 80 + i.lock.Lock() 81 + i.nextUniqueID++ 82 + x := i.nextUniqueID 83 + i.lock.Unlock() 84 + return x 74 85 } 75 86 76 87 func newIndex() *index {
+4
internal/core/runtime/index.go
··· 29 29 return getKey(s) 30 30 } 31 31 32 + func (r *Runtime) NextUniqueID() uint64 { 33 + return r.index.getNextUniqueID() 34 + } 35 + 32 36 func (r *Runtime) LabelStr(l adt.Feature) string { 33 37 return l.IdentString(r) 34 38 }
+5 -4
internal/core/subsume/structural.go
··· 58 58 } 59 59 60 60 func (s *subsumer) structural(a, b adt.Conjunct) bool { 61 - if y, ok := b.Expr().(*adt.LetReference); ok { 62 - return s.conjunct(a, s.c(b.Env, y.X)) 63 - } 64 61 if isBottomConjunct(b) { 65 62 return true 66 63 } ··· 99 96 } 100 97 101 98 case *adt.LetReference: 102 - return s.conjunct(s.c(a.Env, x.X), b) 99 + if y, ok := b.Elem().(*adt.LetReference); ok && x.Label == y.Label { 100 + if s.node(a.Env, x.UpCount) == s.node(b.Env, y.UpCount) { 101 + return true 102 + } 103 + } 103 104 104 105 case *adt.SelectorExpr: 105 106 if y, ok := a.Elem().(*adt.SelectorExpr); ok &&
+3
internal/core/validate/validate.go
··· 98 98 } 99 99 100 100 for _, a := range x.Arcs { 101 + if a.Label.IsLet() { 102 + continue 103 + } 101 104 if !v.AllErrors && v.err != nil { 102 105 break 103 106 }
+4 -17
internal/core/walk/walk.go
··· 31 31 } 32 32 33 33 type Visitor struct { 34 - // TODO: lets really should be special fields 35 - letDone map[adt.Expr]bool 36 - 37 34 Feature func(f adt.Feature, src adt.Node) 38 35 Before func(adt.Node) bool 39 36 } 40 37 41 - func (w *Visitor) init() { 42 - if w.letDone == nil { 43 - w.letDone = map[adt.Expr]bool{} 44 - } 45 - } 46 - 47 38 func (w *Visitor) Elem(x adt.Elem) { 48 - w.init() 49 39 w.node(x) 50 40 } 51 41 ··· 92 82 93 83 case *adt.LetReference: 94 84 w.feature(x.Label, x) 95 - if w.letDone == nil { 96 - w.letDone = map[adt.Expr]bool{} 97 - } 98 - if !w.letDone[x.X] { 99 - w.letDone[x.X] = true 100 - w.node(x.X) 101 - } 102 85 103 86 case *adt.SelectorExpr: 104 87 w.node(x.X) ··· 152 135 w.node(x.Value) 153 136 154 137 case *adt.OptionalField: 138 + w.feature(x.Label, x) 139 + w.node(x.Value) 140 + 141 + case *adt.LetField: 155 142 w.feature(x.Label, x) 156 143 w.node(x.Value) 157 144