cue-lang / cue

The home of the CUE language! Validate and define text-based and dynamic configuration
https://cuelang.org
Apache License 2.0
5.14k stars 294 forks source link

cue: Value.ReferencePath gives wrong path for reference "within" a value #2967

Open myitcv opened 8 months ago

myitcv commented 8 months ago

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

$ cue version
v0.8.0

Does this issue reproduce with the latest release?

Yes

What did you do?

# tidy to start
go mod tidy

# eval x.cue
exec cue eval x.cue
cmp stdout eval-x.golden

# eval alternate.cue
exec cue eval alternate.cue
cmp stdout eval-alternate.golden

# go run
go run .
cmp stdout referencepath.golden

-- go.mod --
module github.com/myitcv/playground

go 1.22

require cuelang.org/go v0.8.0

-- input.json --
{
    "x": 5,
    "a": {
        "b": {
            "c": "test",
            "d": [
                1,
                2,
                3
            ]
        }
    }
}
-- main.go --
package main

import (
    "fmt"

    "cuelang.org/go/cue"
    "cuelang.org/go/cue/cuecontext"
    "cuelang.org/go/cue/load"
)

func main() {
    ctx := cuecontext.New()
    bis := load.Instances([]string{"x.cue"}, nil)
    v := ctx.BuildInstance(bis[0])
    inner := v.LookupPath(cue.ParsePath("outer.inner"))
    b := inner.LookupPath(cue.ParsePath("b"))
    rootVal, aPath := b.ReferencePath()
    fmt.Printf("rootVal: %v\naPath: %v\n", rootVal, aPath)
}
-- x.cue --
outer: inner: {
    a: int
    b: a
}

result: outer.inner & {
    a: 5
}
-- alternate.cue --
outer: inner: {
    a: int
    b: outer.inner.a
}

result: outer.inner & {
    a: 5
}
-- eval-x.golden --
outer: {
    inner: {
        a: int
        b: int
    }
}
result: {
    a: 5
    b: 5
}
-- eval-alternate.golden --
outer: {
    inner: {
        a: int
        b: int
    }
}
result: {
    a: 5
    b: int
}
-- referencepath.golden --
rootVal: {
    a: int
    b: int
}
aPath: a

What did you expect to see?

Passing test

What did you see instead?

# tidy to start (0.044s)
# eval x.cue (0.012s)
# eval alternate.cue (0.012s)
# go run (0.260s)
> go run .
[stdout]
rootVal: {
        outer: {
                inner: {
                        a: int
                        b: int
                }
        }
        result: {
                a: 5
                b: 5
        }
}
aPath: outer.inner.a

> cmp stdout referencepath.golden
--- stdout
+++ referencepath.golden
@@ -1,13 +1,5 @@
 rootVal: {
-       outer: {
-               inner: {
-                       a: int
-                       b: int
-               }
-       }
-       result: {
-               a: 5
-               b: 5
-       }
+       a: int
+       b: int
 }
-aPath: outer.inner.a
+aPath: a

FAIL: /tmp/testscript2960103954/repro.txtar/script.txtar:14: stdout and referencepath.golden differ

That the reference path for b is reported as outer.inner.a (from the root value) is I think wrong. Because if that were the actual reference (as shown in alternate.cue) then we get a different result.

I think cue.Value.ReferencePath() should be precise here.

mpvl commented 8 months ago

Working as intended. ReferencePath reflects semantics, not syntax. You can use Split or Expr and call Source on the respective conjuncts to get access tot he syntax elements that into a Value.