Skip to content

Conversation

jnm2
Copy link
Contributor

@jnm2 jnm2 commented Sep 4, 2025

Fixes #1371

I spread a wide net and put no effort toward deduplicating so far, after seeing the wide variety in types of update. I am open to suggestion on that.

@@ -359,7 +361,7 @@ In both of the above cases, a cast expression can be used to explicitly convert

A member lookup is the process whereby the meaning of a name in the context of a type is determined. A member lookup can occur as part of evaluating a *simple_name* ([§12.8.4](expressions.md#1284-simple-names)) or a *member_access* ([§12.8.7](expressions.md#1287-member-access)) in an expression. If the *simple_name* or *member_access* occurs as the *primary_expression* of an *invocation_expression* ([§12.8.10.2](expressions.md#128102-method-invocations)), the member is said to be *invoked*.

If a member is a method or event, or if it is a constant, field or property of either a delegate type ([§20](delegates.md#20-delegates)) or the type `dynamic` ([§8.2.4](types.md#824-the-dynamic-type)), then the member is said to be *invocable.*
If a member is a method or event, or if it is a constant, field or property whose evaluated value is either of a delegate type ([§20](delegates.md#20-delegates)) or the type `dynamic` ([§8.2.4](types.md#824-the-dynamic-type)), then the member is said to be *invocable.*
Copy link
Contributor Author

@jnm2 jnm2 Sep 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change enables:

class C
{
    void M()
    {
        Prop();
    }

    private System.Action f;
    public ref System.Action Prop => ref f;
}

Since the property type is ref System.Action which is not a delegate type, but the property's evaluated value is of type System.Action.

@@ -454,23 +456,23 @@ Once a particular function member has been identified at binding-time, possibly
> </tr>
> <tr>
> <td><code>P = value</code></td>
> <td>The set accessor of the property <code>P</code> in the containing class or struct is invoked with the argument list <code>(value)</code>. A compile-time error occurs if <code>P</code> is read-only. If <code>P</code> is not <code>static</code>, the instance expression is <code>this</code>.</td>
> <td>If <code>P</code> is non-ref-valued, the set accessor of the property <code>P</code> in the containing class or struct is invoked with the argument list <code>(value)</code>. If <code>P</code> is ref-valued, the get accessor of the property <code>P</code> in the containing class or struct is invoked. A compile-time error occurs if <code>P</code> is non-ref-valued and read-only or if <code>P</code> is ref-valued and returns a readonly reference. If <code>P</code> is not <code>static</code>, the instance expression is <code>this</code>.</td>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about the language "returns" and "readonly reference." Is there established language for this?

@@ -2557,9 +2559,9 @@ Each *initializer_target* is followed by an equals sign and either an expression

A member initializer that specifies an expression after the equals sign is processed in the same way as an assignment ([§12.21.2](expressions.md#12212-simple-assignment)) to the target.

A member initializer that specifies an object initializer after the equals sign is a ***nested object initializer***, i.e., an initialization of an embedded object. Instead of assigning a new value to the field or property, the assignments in the nested object initializer are treated as assignments to members of the field or property. Nested object initializers cannot be applied to properties with a value type, or to read-only fields with a value type.
A member initializer that specifies an object initializer after the equals sign is a ***nested object initializer***, i.e., an initialization of an embedded object. Instead of assigning a new value to the field or property, the assignments in the nested object initializer are treated as assignments to members of the field or property. Nested object initializers cannot be applied to properties or indexers with a value type, to ref-valued properties or indexers whose type is a reference to a value type, or to read-only fields with a value type.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likely fixes an older spec bug which failed to mention that this rule applies to indexers as well as properties.


A member initializer that specifies a collection initializer after the equals sign is an initialization of an embedded collection. Instead of assigning a new collection to the target field, property, or indexer, the elements given in the initializer are added to the collection referenced by the target. The target shall be of a collection type that satisfies the requirements specified in [§12.8.17.2.3](expressions.md#1281723-collection-initializers).
A member initializer that specifies a collection initializer after the equals sign is an initialization of an embedded collection. Instead of assigning a new collection to the target field, property, or indexer, the elements given in the initializer are added to the collection referenced by the target. The target shall be of a collection type that satisfies the requirements specified in [§12.8.17.2.3](expressions.md#1281723-collection-initializers). Initialization of an embedded collection cannot be applied to properties or indexers with a value type, to ref-valued properties or indexers whose type is a reference to a value type, or to read-only fields with a value type.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likely fixes an older spec bug which failed to mention that this rule applies to nested collection initializers as well as nested object initializers.

- A property that has only a get accessor is said to be a ***read-only property***. It is a compile-time error for a read-only property to be the target of an assignment.
- A property that has only a set accessor is said to be a ***write-only property***. Except as the target of an assignment, it is a compile-time error to reference a write-only property in an expression.
- A property that has only a get accessor is said to be a ***read-only property***. It is a compile-time error for a read-only property to be the target of an assignment unless the property is ref-valued and returns a writeable reference.
- A property that has only a set accessor is said to be a ***write-only property***. Except as the target of an assignment or as an argument to the `nameof` operator ([§12.8.23](expressions.md#12823-the-nameof-operator)), it is a compile-time error to reference a write-only property in an expression.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likely fixes an older spec bug which was disallowing:

class C
{
    void M()
    {
        _ = nameof(Prop);
    }

    public int Prop { set { } }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Property & indexer access not fully updated for ref get accessors
1 participant