Skip to content

Commit

Permalink
internal/core/adt: allow selectively turning off sharing
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
mpvl committed Dec 7, 2024
1 parent ec9117a commit dc1ef63
Show file tree
Hide file tree
Showing 3 changed files with 258 additions and 7 deletions.
250 changes: 243 additions & 7 deletions cue/testdata/eval/sharing.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,39 @@ issue3062: ok1: {
X: x: A
A: "a"
}

// Test debug facilities to turn of sharing.
debug: {
sharingOn: {
a: b
b: c: 1
}
sharingOff: t1: {
a: b & __no_sharing
b: c: 1
}
sharingOff: t2: {
a: b
a: __no_sharing
b: c: 1
}
sharingOff: t3: {
a: __no_sharing
a: b
b: c: 1
}
}
-- out/eval/stats --
Leaks: 0
Freed: 11
Reused: 4
Freed: 33
Reused: 26
Allocs: 7
Retain: 3
Retain: 7

Unifications: 11
Conjuncts: 18
Disjuncts: 12
-- out/eval --
Unifications: 33
Conjuncts: 49
Disjuncts: 38
-- out/evalalpha --
(struct){
issue3062: (struct){
ok1: (struct){
Expand All @@ -36,6 +58,186 @@ Disjuncts: 12
A: (string){ "a" }
}
}
debug: (struct){
sharingOn: (struct){
a: ~(debug.sharingOn.b)
b: (struct){
c: (int){ 1 }
}
}
sharingOff: (struct){
t1: (struct){
a: (struct){
c: (int){ 1 }
}
b: (struct){
c: (int){ 1 }
}
}
t2: (struct){
a: (struct){
c: (int){ 1 }
}
b: (struct){
c: (int){ 1 }
}
}
t3: (struct){
a: (struct){
c: (int){ 1 }
}
b: (struct){
c: (int){ 1 }
}
}
}
}
}
-- diff/-out/evalalpha<==>+out/eval --
diff old new
--- old
+++ new
@@ -1,9 +1,4 @@
-Errors:
-no sharing
-
-Result:
-(_|_){
- // [eval]
+(struct){
issue3062: (struct){
ok1: (struct){
#S: (string){ "a" }
@@ -19,42 +14,32 @@
A: (string){ "a" }
}
}
- debug: (_|_){
- // [eval]
+ debug: (struct){
sharingOn: (struct){
- a: (struct){
- c: (int){ 1 }
- }
+ a: ~(debug.sharingOn.b)
b: (struct){
c: (int){ 1 }
}
}
- sharingOff: (_|_){
- // [eval]
- t1: (_|_){
- // [eval]
- a: (_|_){
- // [eval] no sharing
- c: (int){ 1 }
- }
- b: (struct){
- c: (int){ 1 }
- }
- }
- t2: (_|_){
- // [eval]
- a: (_|_){
- // [eval] no sharing
- c: (int){ 1 }
- }
- b: (struct){
- c: (int){ 1 }
- }
- }
- t3: (_|_){
- // [eval]
- a: (_|_){
- // [eval] no sharing
+ sharingOff: (struct){
+ t1: (struct){
+ a: (struct){
+ c: (int){ 1 }
+ }
+ b: (struct){
+ c: (int){ 1 }
+ }
+ }
+ t2: (struct){
+ a: (struct){
+ c: (int){ 1 }
+ }
+ b: (struct){
+ c: (int){ 1 }
+ }
+ }
+ t3: (struct){
+ a: (struct){
c: (int){ 1 }
}
b: (struct){
-- out/eval --
Errors:
no sharing

Result:
(_|_){
// [eval]
issue3062: (struct){
ok1: (struct){
#S: (string){ "a" }
#o: (#struct){
x: (string){ "a" }
}
o: (#struct){
x: (string){ "a" }
}
X: (struct){
x: (string){ "a" }
}
A: (string){ "a" }
}
}
debug: (_|_){
// [eval]
sharingOn: (struct){
a: (struct){
c: (int){ 1 }
}
b: (struct){
c: (int){ 1 }
}
}
sharingOff: (_|_){
// [eval]
t1: (_|_){
// [eval]
a: (_|_){
// [eval] no sharing
c: (int){ 1 }
}
b: (struct){
c: (int){ 1 }
}
}
t2: (_|_){
// [eval]
a: (_|_){
// [eval] no sharing
c: (int){ 1 }
}
b: (struct){
c: (int){ 1 }
}
}
t3: (_|_){
// [eval]
a: (_|_){
// [eval] no sharing
c: (int){ 1 }
}
b: (struct){
c: (int){ 1 }
}
}
}
}
}
-- out/compile --
--- in.cue
Expand All @@ -54,4 +256,38 @@ Disjuncts: 12
A: "a"
}
}
debug: {
sharingOn: {
a: 〈0;b〉
b: {
c: 1
}
}
sharingOff: {
t1: {
a: (〈0;b〉 & _|_(no sharing))
b: {
c: 1
}
}
}
sharingOff: {
t2: {
a: 〈0;b〉
a: _|_(no sharing)
b: {
c: 1
}
}
}
sharingOff: {
t3: {
a: _|_(no sharing)
a: 〈0;b〉
b: {
c: 1
}
}
}
}
}
12 changes: 12 additions & 0 deletions internal/core/adt/conjunct.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import (
"fmt"

"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/errors"
"cuelang.org/go/cue/token"
)

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

// Literal conjuncts

// NoSharingSentinel is a sentinel value that is used to disable sharing of
// nodes. We make this an error to make it clear that we discard the value.
var NoShareSentinel = &Bottom{
Err: errors.Newf(token.NoPos, "no sharing"),
}

func (n *nodeContext) insertValueConjunct(env *Environment, v Value, id CloseInfo) {
n.updateCyclicStatusV3(id)

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

case *Bottom:
if x == NoShareSentinel {
n.unshare()
return
}
id.cc.hasNonTop = true
n.addBottom(x)
return
Expand Down
3 changes: 3 additions & 0 deletions internal/core/compile/predeclared.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ func predeclared(n *ast.Ident) adt.Expr {
return quoBuiltin
case "rem", "__rem":
return remBuiltin

case "__no_sharing":
return adt.NoShareSentinel
}

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

0 comments on commit dc1ef63

Please sign in to comment.