cue icon indicating copy to clipboard operation
cue copied to clipboard

evaluator: allow source value for `for` comprehension to be partially evaluated

Open myitcv opened this issue 3 years ago • 3 comments

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

$ cue version
cue version v0.0.0-20220824153543-547c4390430c

       -compiler gc
     CGO_ENABLED 1
          GOARCH arm64
            GOOS linux
             vcs git
    vcs.revision 547c4390430c9ab4274a8f5aa3548dacfc1f4981
        vcs.time 2022-08-24T15:35:43Z
    vcs.modified false

Does this issue reproduce with the latest release?

Yes

What did you do?

# z.cue - unrolled comprehension
exec cue eval x.cue z.cue
cmp stdout stdout.golden

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

-- x.cue --
package x

#AllOutputs: {
	reject:   string
	resource: string
	retry: {
		output: #Output
	}
}

o: #Output & {
	retry: {
		output: {
			reject: "ok"
		}
	}
}
-- y.cue --
package x

#Output: or([ for name, config in #AllOutputs {
	(name): config
}])
-- z.cue --
package x

#Output: {
	reject: string
} | {
	resource: string
} | {
	retry: {
		output: null | #Output
	}
}
-- stdout.golden --
#AllOutputs: {
    reject:   string
    resource: string
    retry: {
        output: {
            reject: string
        } | {
            resource: string
        } | {
            retry: {
                output: null
            }
        }
    }
}
#Output: {
    reject: string
} | {
    resource: string
} | {
    retry: {
        output: null
    }
}
o: {
    retry: {
        output: {
            reject: "ok"
        }
    }
}

What did you expect to see?

Passing test.

What did you see instead?

# z.cue - unrolled comprehension (0.017s)
# y.cue - comprehension (0.014s)
> exec cue eval x.cue y.cue
[stderr]
2.retry: structural cycle:
    ./y.cue:3:13
[exit status 1]
FAIL: /tmp/testscript1560619719/repro.txtar/script.txt:6: unexpected command failure

Note that z.cue is the unrolled version of y.cue, so I think these two should be identical in behaviour.

Note this is note fixed by https://review.gerrithub.io/c/cue-lang/cue/+/542674.

Also, this appears to have been an issue for some time. At least as far back as v0.3.2.

myitcv avatar Aug 24 '22 16:08 myitcv

See

#Output: or([ for name, config in #AllOutputs { (name): config }])

#AllOutputs: {
	reject:   string
	resource: string
	retry:  output: #Output
}

The source for a for comprehension must be fully evaluated before it is used. This is due to how "void" arcs are handled. I guess theoretically this could be done "lazily", but this more complicated and currently it is defined as such.

As a result, evaluating #Output triggers the evaluation of #AllOutput, which in turn triggers the evaluation of #Output (a cycle), before the comprehension can be evaluated and thus before a call to or can be made.

mpvl avatar Aug 24 '22 20:08 mpvl

See https://review.gerrithub.io/c/cue-lang/cue/+/533224 for feasibility.

mpvl avatar Aug 25 '22 07:08 mpvl

Just noting per earlier discussion, that in the repro above, z.cue is the "unrolled" version of the comprehension in y.cue. exec cue eval x.cue z.cue shows there is not a cycle, so arguably exec cue eval x.cue y.cue should give the same result. Therefore, this issue is tracking ensuring that the comprehension version behaves like the "unrolled" version.

myitcv avatar Aug 25 '22 17:08 myitcv