Skip to content

Commit dc1ef63

Browse files
committed
internal/core/adt: allow selectively turning off sharing
Some bugs only manifest itself when a combination of sharing and not sharing of nodes occurs. It is hard to write tests for these bugs, as the sharing algorithm is continuously evolving: a construct that disables sharing right now, might not do so in the future. We add a __no_sharing directive that, when unified with another value, will guarantee that this value is not shared. Issue #3601 Signed-off-by: Marcel van Lohuizen <[email protected]> Change-Id: Ib3d2c5783761583072e46107fbd8ba84827e6f70 Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1205230 TryBot-Result: CUEcueckoo <[email protected]> Unity-Result: CUE porcuepine <[email protected]> Reviewed-by: Matthew Sackman <[email protected]>
1 parent ec9117a commit dc1ef63

File tree

3 files changed

+258
-7
lines changed

3 files changed

+258
-7
lines changed

cue/testdata/eval/sharing.txtar

+243-7
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,39 @@ issue3062: ok1: {
99
X: x: A
1010
A: "a"
1111
}
12+
13+
// Test debug facilities to turn of sharing.
14+
debug: {
15+
sharingOn: {
16+
a: b
17+
b: c: 1
18+
}
19+
sharingOff: t1: {
20+
a: b & __no_sharing
21+
b: c: 1
22+
}
23+
sharingOff: t2: {
24+
a: b
25+
a: __no_sharing
26+
b: c: 1
27+
}
28+
sharingOff: t3: {
29+
a: __no_sharing
30+
a: b
31+
b: c: 1
32+
}
33+
}
1234
-- out/eval/stats --
1335
Leaks: 0
14-
Freed: 11
15-
Reused: 4
36+
Freed: 33
37+
Reused: 26
1638
Allocs: 7
17-
Retain: 3
39+
Retain: 7
1840

19-
Unifications: 11
20-
Conjuncts: 18
21-
Disjuncts: 12
22-
-- out/eval --
41+
Unifications: 33
42+
Conjuncts: 49
43+
Disjuncts: 38
44+
-- out/evalalpha --
2345
(struct){
2446
issue3062: (struct){
2547
ok1: (struct){
@@ -36,6 +58,186 @@ Disjuncts: 12
3658
A: (string){ "a" }
3759
}
3860
}
61+
debug: (struct){
62+
sharingOn: (struct){
63+
a: ~(debug.sharingOn.b)
64+
b: (struct){
65+
c: (int){ 1 }
66+
}
67+
}
68+
sharingOff: (struct){
69+
t1: (struct){
70+
a: (struct){
71+
c: (int){ 1 }
72+
}
73+
b: (struct){
74+
c: (int){ 1 }
75+
}
76+
}
77+
t2: (struct){
78+
a: (struct){
79+
c: (int){ 1 }
80+
}
81+
b: (struct){
82+
c: (int){ 1 }
83+
}
84+
}
85+
t3: (struct){
86+
a: (struct){
87+
c: (int){ 1 }
88+
}
89+
b: (struct){
90+
c: (int){ 1 }
91+
}
92+
}
93+
}
94+
}
95+
}
96+
-- diff/-out/evalalpha<==>+out/eval --
97+
diff old new
98+
--- old
99+
+++ new
100+
@@ -1,9 +1,4 @@
101+
-Errors:
102+
-no sharing
103+
-
104+
-Result:
105+
-(_|_){
106+
- // [eval]
107+
+(struct){
108+
issue3062: (struct){
109+
ok1: (struct){
110+
#S: (string){ "a" }
111+
@@ -19,42 +14,32 @@
112+
A: (string){ "a" }
113+
}
114+
}
115+
- debug: (_|_){
116+
- // [eval]
117+
+ debug: (struct){
118+
sharingOn: (struct){
119+
- a: (struct){
120+
- c: (int){ 1 }
121+
- }
122+
+ a: ~(debug.sharingOn.b)
123+
b: (struct){
124+
c: (int){ 1 }
125+
}
126+
}
127+
- sharingOff: (_|_){
128+
- // [eval]
129+
- t1: (_|_){
130+
- // [eval]
131+
- a: (_|_){
132+
- // [eval] no sharing
133+
- c: (int){ 1 }
134+
- }
135+
- b: (struct){
136+
- c: (int){ 1 }
137+
- }
138+
- }
139+
- t2: (_|_){
140+
- // [eval]
141+
- a: (_|_){
142+
- // [eval] no sharing
143+
- c: (int){ 1 }
144+
- }
145+
- b: (struct){
146+
- c: (int){ 1 }
147+
- }
148+
- }
149+
- t3: (_|_){
150+
- // [eval]
151+
- a: (_|_){
152+
- // [eval] no sharing
153+
+ sharingOff: (struct){
154+
+ t1: (struct){
155+
+ a: (struct){
156+
+ c: (int){ 1 }
157+
+ }
158+
+ b: (struct){
159+
+ c: (int){ 1 }
160+
+ }
161+
+ }
162+
+ t2: (struct){
163+
+ a: (struct){
164+
+ c: (int){ 1 }
165+
+ }
166+
+ b: (struct){
167+
+ c: (int){ 1 }
168+
+ }
169+
+ }
170+
+ t3: (struct){
171+
+ a: (struct){
172+
c: (int){ 1 }
173+
}
174+
b: (struct){
175+
-- out/eval --
176+
Errors:
177+
no sharing
178+
179+
Result:
180+
(_|_){
181+
// [eval]
182+
issue3062: (struct){
183+
ok1: (struct){
184+
#S: (string){ "a" }
185+
#o: (#struct){
186+
x: (string){ "a" }
187+
}
188+
o: (#struct){
189+
x: (string){ "a" }
190+
}
191+
X: (struct){
192+
x: (string){ "a" }
193+
}
194+
A: (string){ "a" }
195+
}
196+
}
197+
debug: (_|_){
198+
// [eval]
199+
sharingOn: (struct){
200+
a: (struct){
201+
c: (int){ 1 }
202+
}
203+
b: (struct){
204+
c: (int){ 1 }
205+
}
206+
}
207+
sharingOff: (_|_){
208+
// [eval]
209+
t1: (_|_){
210+
// [eval]
211+
a: (_|_){
212+
// [eval] no sharing
213+
c: (int){ 1 }
214+
}
215+
b: (struct){
216+
c: (int){ 1 }
217+
}
218+
}
219+
t2: (_|_){
220+
// [eval]
221+
a: (_|_){
222+
// [eval] no sharing
223+
c: (int){ 1 }
224+
}
225+
b: (struct){
226+
c: (int){ 1 }
227+
}
228+
}
229+
t3: (_|_){
230+
// [eval]
231+
a: (_|_){
232+
// [eval] no sharing
233+
c: (int){ 1 }
234+
}
235+
b: (struct){
236+
c: (int){ 1 }
237+
}
238+
}
239+
}
240+
}
39241
}
40242
-- out/compile --
41243
--- in.cue
@@ -54,4 +256,38 @@ Disjuncts: 12
54256
A: "a"
55257
}
56258
}
259+
debug: {
260+
sharingOn: {
261+
a: 〈0;b〉
262+
b: {
263+
c: 1
264+
}
265+
}
266+
sharingOff: {
267+
t1: {
268+
a: (〈0;b〉 & _|_(no sharing))
269+
b: {
270+
c: 1
271+
}
272+
}
273+
}
274+
sharingOff: {
275+
t2: {
276+
a: 〈0;b〉
277+
a: _|_(no sharing)
278+
b: {
279+
c: 1
280+
}
281+
}
282+
}
283+
sharingOff: {
284+
t3: {
285+
a: _|_(no sharing)
286+
a: 〈0;b〉
287+
b: {
288+
c: 1
289+
}
290+
}
291+
}
292+
}
57293
}

internal/core/adt/conjunct.go

+12
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import (
1818
"fmt"
1919

2020
"cuelang.org/go/cue/ast"
21+
"cuelang.org/go/cue/errors"
22+
"cuelang.org/go/cue/token"
2123
)
2224

2325
// This file contains functionality for processing conjuncts to insert the
@@ -554,6 +556,12 @@ func (n *nodeContext) addNotify2(v *Vertex, c CloseInfo) []receiver {
554556

555557
// Literal conjuncts
556558

559+
// NoSharingSentinel is a sentinel value that is used to disable sharing of
560+
// nodes. We make this an error to make it clear that we discard the value.
561+
var NoShareSentinel = &Bottom{
562+
Err: errors.Newf(token.NoPos, "no sharing"),
563+
}
564+
557565
func (n *nodeContext) insertValueConjunct(env *Environment, v Value, id CloseInfo) {
558566
n.updateCyclicStatusV3(id)
559567

@@ -613,6 +621,10 @@ func (n *nodeContext) insertValueConjunct(env *Environment, v Value, id CloseInf
613621
return
614622

615623
case *Bottom:
624+
if x == NoShareSentinel {
625+
n.unshare()
626+
return
627+
}
616628
id.cc.hasNonTop = true
617629
n.addBottom(x)
618630
return

internal/core/compile/predeclared.go

+3
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ func predeclared(n *ast.Ident) adt.Expr {
6060
return quoBuiltin
6161
case "rem", "__rem":
6262
return remBuiltin
63+
64+
case "__no_sharing":
65+
return adt.NoShareSentinel
6366
}
6467

6568
if r, ok := predefinedRanges[n.Name]; ok {

0 commit comments

Comments
 (0)