Perhaps I'm misunderstanding the concept of a readonly struct, but I would think this code should not compile:
public readonly struct TwoPoints
{
    private readonly Point one;
    private readonly Point two;
    void Foo()
    {
        // compiler error:  Error CS1648  Members of readonly field 'TwoPoints.one'
        // cannot be modified (except in a constructor or a variable initializer)
        one.X = 5;
        //no compiler error! (and one is not changed)
        one.Offset(5, 5);
    }
 }
(I'm using C# 7.3.) Am I missing something?
 
                        
There is no way for compiler to figure out that
Offsetmethod mutatesPointstruct members. However,readonlystruct field is handled differently compared to non-readonly one. Consider this (not readonly) struct:onefield is readonly buttwois not. Now, when you call a method onreadonlystruct field - a copy of struct is passed to that method asthis. And if method mutates struct members - than this copy members are mutated. For this reason you don't observe any changes tooneafter method is called - it has not been changed but copy was.twofield is not readonly, and struct itself (not copy) is passed toOffsetmethod, and so if method mutates members - you can observe them changed after method call.So, this is allowed because it cannot break immutability contract of your
readonly struct. All fields ofreadonly structshould bereadonly, and methods called on readonly struct field cannot mutate it, they can only mutate a copy.If you are interested in "official source" for this - specification (7.6.4 Member access) says that:
There is target type, andIis member being accessed.First part says that if we access instance readonly field of a struct, outside of constructor, the result is value. In second case, where instance field is not readonly - result is variable.
Then section "7.5.5 Function member invocation" says (
Ehere is instance expression, so for exampleoneandtwoabove):As we saw above, readonly struct field access results in a
value, not a variable and so,Eis not classified as variable.