You defined z as a constant. That’s why you cannot modify it later. You can either define the value of the constant at the point of creation, or make z a variable (using var instead of let) if you want its value to change later.
That looks like a bug, You're using z outside of the scope that it's declared, and you're uaing z inside z, which is not defined in the scope. Maybe you can file a bug report?
Aside from that, passing it through queue.sync may be more idiomatic:
DispatchQueue.sync takes a regular non-escaping closure, so there's hardly anyway to do precisely as you want as the compiler doesn't know if it'll be call exactly once. What about what I suggested:
It's not obvious to the compiler. queue.sync{ [...] } is just an API call to the compiler with a non-escaping closure.
The compiler does not know that the closure is executed exactly once.
It must assume that the closure is not called at all or multiple times.
That's why you can not use it to initialise a constant.
That is a known limitation and one reason for the generic version of sync:
func sync<T>(execute work: () throws -> T) rethrows -> T
This allows you to initialise your constant like this:
let z: Int = queue.sync { 1 }
The implementation of this function could look something like this: