You have found a bug in the desugarer. It is in logic that is intended to solve the following problem:
Correct execution:
$ jsonnet -e '{ foo:: "field_name", bar: { [self.foo] +: "field_value" } }'
{
"bar": {
"field_name": "field_value"
}
}
Naive desugaring:
$ jsonnet -e '{ foo:: "field_name", bar: { [self.foo] : super[self.foo] + "field_value" } }'
RUNTIME ERROR: Field does not exist: foo
Actual desugaring (simplified for clarity):
{
foo:: "field_name",
bar: local $outer_self = self; {
[self.foo]: super[$outer_self.foo] + "field_value"
},
}
Except in your case it has gone too far and hoisted it out of a deeper object when a) it could have left it in place, b) moving it has changed the behavior. The bug is in desugaring.cpp in the definition of the SubstituteSelfSuper pass, which does not stop at a new object subtree.
As a work around, you can hoist out the local manually, which will avoid this desugaring logic being triggered:
local
foo = {a: "y"}{b: super.a}.b
{[
foo]+: 1}
Note that the spec is correct but actually quite vague because it refers to e[$outerself/self,$outersuper/super] before defining what [ ] actually means. We should also fix that by using the definition of capture avoiding substitution that is defined further down the spec.