That's (usually) only true for the very first '->' in a chain and as you said, depends on the compiler figuring out if the pointer indirection can be resolved at compile time.
A chain of '.' on the other hand is always guaranteed to be resolved into a single offset at compile time.
> Why does C even have a two member selection operators?
Because using `(*ptr).member` everywhere is annoying. There's plenty of times you want or need to have direct access to a member rather than always dereferencing a pointer.
It's too bad C's pointer-deref operator is prefix instead of postfix. In Pascal it's ^ so you write ptr^.member and there's no special -> operator. Even better, declarations and expressions would read intuitively left-to-right instead of spiraling out through stars on the left and brackets on the right.
C was practically a portable assembler when it was designed, and it was likely helpful for performance reasoning that all indirections were clearly visible.