The compiler doesn't do that level of analysis to see that the branch is never taken -- at least not at this borrow checker phase. Optimization will surely wipe that out, but that's later.
Rust intentionally doesn't do value-level analysis like this, so that when you're testing stuff you can set things to constants and it's not going to change your initialization and borrow checking errors.
Because the current code b = false; if statement block is not executed so I do not think the error will be reported, and no matter b = false or b = true the program will report the same error. This is a bit surprising and confusing to me
Sorry, I don't understand at all what you are asking. If you are having trouble expressing yourself reasonably well in English, please seek help with translating your question.
Your latest code snippet doesn't contain any errors – regardless of whether the variable x is true or false, it is a valid program. It either prints something or it doesn't, but it doesn't ever attempt to do anything potentially invalid. There is no reason why any errors should be reported by the compiler for that piece of code.
People have already responded to your original question. Rust intentionally doesn't try to guess as many of your runtime values as possible at compile time for the purposes of type checking, because then the following problem could happen:
you write a function similar to the above that depends on an argument passed by the user
you set your argument to false in a test
your code compiles, your test passes, and you happily release your code
someone using your code sets the same argument to true
now your code won't compile and they will be SadTM, because they thought your code that they are trying to use was working, but it is in fact incorrect.
To avoid such situations, type checking has to require that a piece of code is valid, regardless of the concrete values any variables happen to have during any particular execution.
This is the same reason why Rust generics require explicit trait bounds for all capabilities to be used, unlike C++ templates, for example. It is the same reason why conflicting implementations of 3rd-party traits for 3rd-party types aren't allowed. It's all the same spiel – you want your code to be reliable and not blow up in the user's face, so the compiler has to anticipate all possible circumstances in which it may be used.
I'm sorry – I was as careful as I can. If you don't understand this explanation, chances are you wouldn't understand any other "official" explanation, either. At this point, I can't say anything more.
I searched for a while, and sadly no official documemtation that clarifies how move semantics actually works is found. The exactly same question is here: