Skip to content

evalv3: (x & y).z pattern error at current master #3685

Open
@loisch

Description

I'm opening this as a separate issue because I don't know if the root cause is the same as in #3672. This reproducer only has 25 lines of code and works with 0.11.1 with both evaluators but not with v3 with current master. It seems to be triggered by the (x & y).z pattern.

What version of CUE are you using (cue version)?

Current build of master branch (latest commit "internal/core/adt: fix constraints deduplication")

cue version v0.12.0-loisch

go version go1.22.1
      -buildmode exe
       -compiler gc
        -ldflags -X cuelang.org/go/cmd/cue/cmd.version=v0.12.0-loisch
     CGO_ENABLED 1
          GOARCH arm64
            GOOS darwin
             vcs git
    vcs.revision 053f47b1a8cdc2419d762aff33e479f8d737a606
        vcs.time 2025-01-17T17:06:42Z
    vcs.modified false
cue.lang.version v0.12.0

Does this issue reproduce with the latest stable release?

No. Works with old and new evaluator in release 0.11 .1.

What did you do?

Run testscript

# evalv2
env CUE_EXPERIMENT=evalv3=0
exec cue eval out.cue
cmp stdout stdout.golden

# evalv3
env CUE_EXPERIMENT=evalv3=1
exec cue eval out.cue
cmp stdout stdout.golden

-- out.cue --
import "strings"

#ConfigText: string | {UseSectionName: true}

#ConfigTextRule: #ConfigText | {Append: #ConfigText}


#FinDefSetOfConfigText: {
	Only: #ConfigTextRule
	let str = (#orgForConfigText & {source: Only}).orgSyntax
	orgSyntax: "Only \(str)"
}

#orgForConfigText: {
	IN=source: #ConfigTextRule
	orgSyntax: [
		if IN.UseSectionName != _|_ {
			"UseSectionName"
		},
		"Impossible: \(IN)"
	][0]
}

works1: #FinDefSetOfConfigText & { Only: { UseSectionName: true } }

-- stdout.golden --
#ConfigText: string | {
    UseSectionName: true
}
#ConfigTextRule: string | {
    UseSectionName: true
} | {
    Append: string | {
        UseSectionName: true
    }
}
#FinDefSetOfConfigText: {
    let str = (#orgForConfigText & {
        source: Only
    }).orgSyntax
    Only: string | {
        UseSectionName: true
    } | {
        Append: string | {
            UseSectionName: true
        }
    }
    orgSyntax: "Only \(str)"
}
#orgForConfigText: {
    source: string | {
        UseSectionName: true
    } | {
        Append: string | {
            UseSectionName: true
        }
    }
    orgSyntax: [
        if IN.UseSectionName != _|_ // explicit error (_|_ literal) in source
        {
            "UseSectionName"
        }, "Impossible: \(IN)"][0]
}
works1: {
    Only: {
        UseSectionName: true
    }
    orgSyntax: "Only UseSectionName"
}

What did you expect to see?

A passing test

# evalv2 (0.069s)
# evalv3 (0.045s)
PASS

Interpretation / Fixes

There are two fixes for current master.

a) introducing a let-binding in the "caller" #FinDefSetOfConfigText

--- test-v3.cue	2025-01-18 17:44:55.378447729 +0100
+++ test-v3-fix1.cue	2025-01-18 17:43:21.693329534 +0100
@@ -7,7 +7,8 @@

 #FinDefSetOfConfigText: {
 	Only: #ConfigTextRule
-	let str = (#orgForConfigText & {source: Only}).orgSyntax
+	let org = (#orgForConfigText & {source: Only})
+	let str = org.orgSyntax
 	orgSyntax: "Only \(str)"
 }

and b) not implicitly unifying source with { UseSectionName: _ } in the "callee" but instead creating a new value different from the passed argument and unifying that value:

--- test-v3.cue	2025-01-18 18:00:02.323823497 +0100
+++ test-v3-fix2.cue	2025-01-18 17:44:26.105990733 +0100
@@ -14,7 +14,7 @@
 #orgForConfigText: {
 	IN=source: #ConfigTextRule
 	orgSyntax: [
-		if IN.UseSectionName != _|_ {
+		if (IN & { UseSectionName: _}) != _|_ {
 			"UseSectionName"
 		},
 		"Impossible: \(IN)"

This shouldn't change anything for the let bindings in the caller but it does. I have absolutely no idea how the evaluator works so I'm only guessing. This problem could arise due to some kind of "call by reference" instead of "call by value" semantics of unification when using the (x & y).z pattern. It feels like a failed unification of source in #orgForConfigText is somehow "leaking" into to the caller (#FinDefOfConfigText) but only if the (x & y).z pattern is used.

What did you see instead?

# evalv2 (0.529s)
# evalv3 (0.057s)
> env CUE_EXPERIMENT=evalv3=1
> exec cue eval out.cue
[stdout]
#ConfigText: string | {
    UseSectionName: true
}
#ConfigTextRule: string | {
    UseSectionName: true
} | {
    Append: string | {
        UseSectionName: true
    }
}
#FinDefSetOfConfigText: {
    Only: string | {
        UseSectionName: true
    } | {
        Append: string | {
            UseSectionName: true
        }
    }
    orgSyntax: "Only "
}
#orgForConfigText: {
    source: string | {
        UseSectionName: true
    } | {
        Append: string | {
            UseSectionName: true
        }
    }
    orgSyntax: [
        if IN.UseSectionName != _|_ // explicit error (_|_ literal) in source
        {
            "UseSectionName"
        }, "Impossible: \(IN)"][0]
}
works1: {
    Only: {
        UseSectionName: true
    }
    orgSyntax: "Only "
}
> cmp stdout stdout.golden
diff stdout stdout.golden
--- stdout
+++ stdout.golden
@@ -9,6 +9,9 @@
     }
 }
 #FinDefSetOfConfigText: {
+    let str = (#orgForConfigText & {
+        source: Only
+    }).orgSyntax
     Only: string | {
         UseSectionName: true
     } | {
@@ -16,7 +19,7 @@
             UseSectionName: true
         }
     }
-    orgSyntax: "Only "
+    orgSyntax: "Only \(str)"
 }
 #orgForConfigText: {
     source: string | {
@@ -36,5 +39,5 @@
     Only: {
         UseSectionName: true
     }
-    orgSyntax: "Only "
+    orgSyntax: "Only UseSectionName"
 }

FAIL: ../let.txtar:9: stdout and stdout.golden differ
failed run

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions