This is scary. I want the tool to tell me "I can't synthesize this" because when it does, it might infer characteristics of the design that I might not want.
Do you have some kind of paper or detailed explanation about this part?
Sometimes a bad design is not bad because it's badly written, it's bad because it's not complying with some timing constraints or because the synthesis tool decided to infer some crazy system from the code the designer wrote.
In Cx you can't create latches, loops work for combinatorial logic and synchronous logic alike, and all in all there are no unsynthesizable constructs. Finding out if a piece of code will result in unacceptable performance is a different problem, I hope to have the compiler kind of "guide" you on this kind of things.
That's a workflow where optimization requires knowing the internals and how they interact, but you can ignore such things if you just want correctness. At least in software, that model works well, because the performance of most of the code we write doesn't matter - even in applications where performance is a concern.
Cx supports functions, if and loops for both combinational and synchronous logic. You can have a function that spans over two cycles. You can give parameters to this kind of function just like in software, except that in the end this is all inlined and the state machine is flattened.
The language encourages a higher level of abstraction where you think in terms of blocking reads and data availability rather than "is my signal true". The best is that this can be extended just by changing the port signature, for example to provide rendez-vous style communications (we call it "sync ack" but they're not implemented yet), whereas in HDL you'd have to write a lot of boilerplate code.
Another property is that there is no synthesizable subset in Cx. As far as I know, this is very rare in languages for hardware design, but the language is entirely synthesizable. You never have to think about synthesis versus simulation. Exactly like in software, nobody ever wonders if they can write code that won't run on the processor :-)
And for the example you mention, this is another interesting feature of the language. Because we support sequential loop constructs etc. you can actually write code that works and synthesizes pretty easily, albeit it is slow. And then you can produce a derived version that is optimized :-)