Description
What version of CUE are you using (cue version
)?
cue version v0.12.0-dfe3ae033d26f79649d69c9dee6cc89ff7599c3d
go version go1.22.1
-buildmode exe
-compiler gc
-ldflags -X cuelang.org/go/cmd/cue/cmd.version=v0.12.0-dfe3ae033d26f79649d69c9dee6cc89ff7599c3d
CGO_ENABLED 1
GOARCH arm64
GOOS darwin
vcs git
vcs.revision dfe3ae033d26f79649d69c9dee6cc89ff7599c3d
vcs.time 2025-01-10T08:17:07Z
vcs.modified false
cue.lang.version v0.12.0
Does this issue reproduce with the latest stable release?
Yes, evalv3=1
produces a different result than evalv3=0
but evalv3
also produces a different result with the latest stable release than with the current master.
What did you do?
I've used a slightly different and simplified version of my program from issue #3654 to better understand cue semantics and performance. The testscript below passes for the latest build and shows a difference between the current and the new evaluator (the new evaluator giving the wrong result).
Correct result for cue eval out.cue -e value0
from current evaluator (current master and latest stable release):
Only: [{
UseSectionName: true
}]
orgSyntax: "Only [UseSectionName]"
Wrong result from v0.12.0-dfe3ae033d26f79649d69c9dee6cc89ff7599c3d
:
Only: [{
UseSectionName: true
} | {
UseSectionName: true
Append: string | {
UseSectionName: true
}
} | {
UseSectionName: true
Prepend: string | {
UseSectionName: true
}
}]
orgSyntax: "Only [Append Impossible]"
Here it seems I'd have to prevent a unification between {UseSectionName: true}
and {Append: #ConfigText}
which probably has something do with closedness. It seems the new evaluator handles this differently. I don't even know where this unification happens.
The wrong result from new evaluator with cue version v0.11.1
:
{
Only: [{
UseSectionName: true
}]
AllBut: []
orgSyntax: "AllBut []"
} | {
Only: [{
UseSectionName: true
}]
orgSyntax: "Only [Append Impossible]"
}
The result is wrong because #ConfigText
only has two alternatives string
and { UseSectionName: true }
and this the orgSyntax
value from #orgForConfigText
should never be the string Impossible
because either of the two if
checks should pass:
#ConfigText: string | {UseSectionName: true}
#orgForConfigText: {
IN=source: #ConfigText
orgSyntax: {
let INS = IN & string
let INO = IN & {UseSectionName:_}
[
if INS != _|_ {
json.Marshal(INS)
},
if INO != _|_ {
"UseSectionName"
},
"Impossible"
][0]
}
}
Before the latest fix for #3597 this triggered a panic but the root cause seems to be different because one of the if
s should match.
Reproducer
env CUE_EXPERIMENT=evalv3=1
exec cue eval out.cue -e value0.orgSyntax
stdout 'Only \[Append Impossible\]'
env CUE_EXPERIMENT=evalv3=0
exec cue eval out.cue -e value0.orgSyntax
stdout 'Only \[UseSectionName\]'
-- out.cue --
import "strings"
import "encoding/json"
#FinDefSetElemType: {
#Type!: _
}
#FinDefSetDefinition: {
#Elem!: #FinDefSetElemType
#Alternatives: {
allBut: {
AllBut: [...#Elem.#Type]
}
only: {
Only: [...#Elem.#Type]
}
}
}
#mkFinDefSet: {
#Definition!: #FinDefSetDefinition
#Type: or([for _, v in #Definition.#Alternatives {v}])
}
#FinDefSetElemType: {
#Type: _
toString!: {
_input: #Type
_output: string
}
}
#FinDefSetDefinition: {
#Elem!: #FinDefSetElemType
#Alternatives: {
allBut: {
AllBut: [...#Elem.#Type]
let xs = [for x in AllBut {(#Elem.toString & {_input: x})._output}]
let str = strings.Join(xs, "\",\"")
orgSyntax: "AllBut [\(str)]"
}
only: {
Only: [...#Elem.#Type]
let xs = [for x in Only {(#Elem.toString & {_input: x})._output}]
let str = strings.Join(xs, "\",\"")
orgSyntax: "Only [\(str)]"
}
}
}
#ConfigText: string | {UseSectionName: true}
#ConfigTextRule: #ConfigText | {Append: #ConfigText} | {Prepend: #ConfigText}
#ConfigTextRules: #ConfigTextRule | [#ConfigTextRule, #ConfigTextRule, ...#ConfigTextRule]
#FinDefSetConfigTextElem: #FinDefSetElemType
#FinDefSetConfigTextElem: {
#Type: #ConfigTextRules
}
#FinDefSetOfConfigText: (
#mkFinDefSet & {
#Definition: {#Elem: #FinDefSetConfigTextElem}
}).#Type
#FinDefSetConfigTextElem: {
toString: {
_input: #ConfigTextRules
_output: (#orgForConfigTextRules & {source: _input}).orgSyntax
}
}
#orgForConfigText: {
IN=source: #ConfigText
orgSyntax: {
let INS = IN & string
let INO = IN & {UseSectionName:_}
[
if INS != _|_ {
json.Marshal(INS)
},
if INO != _|_ {
"UseSectionName"
},
"Impossible"
][0]
}
}
#orgForConfigTextRule: {
IN=source: #ConfigTextRule
orgSyntax: {
let INA = IN & {Append: _}
let INP = IN & {Prepend: _}
[
if INA != _|_ {
"Append " + (#orgForConfigText & {source: INA.Append}).orgSyntax
},
if INP != _|_ {
"Prepend " + (#orgForConfigText & {source: INP.Prepend}).orgSyntax
},
(#orgForConfigText & {source: IN}).orgSyntax,
][0]
}
}
#orgForConfigTextRules: {
IN=source: #ConfigTextRules
orgSyntax: {
let INL = IN & [...]
[
if INL != _|_ {
let elems = [for x in IN {(#orgForConfigTextRule & {source: x}).orgSyntax}]
let result = strings.Join(elems, "\",\"")
"[\(result)]"
},
(#orgForConfigTextRule & {source: IN}).orgSyntax,
][0]
}
}
value0: #FinDefSetOfConfigText
value0: Only: [{ UseSectionName: true }]
What did you expect to see?
Same result with new evaluator and with old evaluator.
What did you see instead?
Different result for old and new evaluator.