From 108dffcb9243f59eda4bc0e925fd1fe9b1020951 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Tue, 11 Nov 2025 11:23:34 -0500 Subject: [PATCH 1/7] Add covariant return types feature --- standard/expressions.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/standard/expressions.md b/standard/expressions.md index ecd659836..58b7ce8b3 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -582,7 +582,7 @@ For each argument in an argument list there has to be a corresponding parameter The parameter list used in the following is determined as follows: -- For virtual methods and indexers defined in classes, the parameter list is picked from the first declaration or override of the function member found when starting with the static type of the receiver, and searching through its base classes. +- For virtual methods and indexers defined in classes, the parameter list is picked from the first declaration or override of the function member found when starting with the static type of the receiver, and searching through its base classes. For virtual methods and indexers defined in interfaces, the parameter list is picked from the declaration or override of the function member found in the most derived type among those types containing the declaration of override of the function member. It is a compile-time error if no unique such type exists. - For partial methods, the parameter list of the defining partial method declaration is used. - For all other function members and delegates there is only a single parameter list, which is the one used. @@ -1717,7 +1717,7 @@ The *member_access* is evaluated and classified as follows: - If `E` is a property access, indexer access, variable, or value, the type of which is `T`, and a member lookup ([§12.5](expressions.md#125-member-lookup)) of `I` in `T` with `K` type arguments produces a match, then `E.I` is evaluated and classified as follows: - First, if `E` is a property or indexer access, then the value of the property or indexer access is obtained ([§12.2.2](expressions.md#1222-values-of-expressions)) and E is reclassified as a value. - If `I` identifies one or more methods, then the result is a method group with an associated instance expression of `E`. - - If `I` identifies an instance property, then the result is a property access with an associated instance expression of `E` and an associated type that is the type of the property. If `T` is a class type, the associated type is picked from the first declaration or override of the property found when starting with `T`, and searching through its base classes. + - If `I` identifies an instance property, then the result is a property access with an associated instance expression of `E` and an associated type that is the type of the property. If `T` is a class type, the associated type is picked from the first declaration or override of the property found when starting with `T`, and searching through its base classes. If `T` is an interface type, the associated type is picked from the declaration or override of the property found in the most derived of `T` or its direct or indirect base interfaces. It is a compile-time error if no unique such type exists. - If `T` is a *class_type* and `I` identifies an instance field of that *class_type*: - If the value of `E` is `null`, then a `System.NullReferenceException` is thrown. - Otherwise, if the field is readonly and the reference occurs outside an instance constructor of the class in which the field is declared, then the result is a value, namely the value of the field `I` in the object referenced by `E`. @@ -1999,7 +1999,7 @@ The result of evaluating an *invocation_expression* is classified as follows: - If the *invocation_expression* invokes a returns-no-value method ([§15.6.1](classes.md#1561-general)) or a returns-no-value delegate, the result is nothing. An expression that is classified as nothing is permitted only in the context of a *statement_expression* ([§13.7](statements.md#137-expression-statements)) or as the body of a *lambda_expression* ([§12.21](expressions.md#1221-anonymous-function-expressions)). Otherwise, a binding-time error occurs. - Otherwise, if the *invocation_expression* invokes a returns-by-ref method ([§15.6.1](classes.md#1561-general)) or a returns-by-ref delegate, the result is a variable with an associated type of the return type of the method or delegate. If the invocation is of an instance method, and the receiver is of a class type `T`, the associated type is picked from the first declaration or override of the method found when starting with `T` and searching through its base classes. -- Otherwise, the *invocation_expression* invokes a returns-by-value method ([§15.6.1](classes.md#1561-general)) or returns-by-value delegate, and the result is a value, with an associated type of the return type of the method or delegate. If the invocation is of an instance method, and the receiver is of a class type `T`, the associated type is picked from the first declaration or override of the method found when starting with `T` and searching through its base classes. +- Otherwise, the *invocation_expression* invokes a returns-by-value method ([§15.6.1](classes.md#1561-general)) or returns-by-value delegate, and the result is a value, with an associated type of the return type of the method or delegate. If the invocation is of an instance method, and the receiver is of a class type `T`, the associated type is picked from the first declaration or override of the method found when starting with `T` and searching through its base classes. If the invocation is of an instance method, and the receiver is of an interface type `T`, the associated type is picked from the declaration or override of the method found in the most derived interface from among `T` and its direct and indirect base interfaces. It is a compile-time error if no unique such type exists. #### 12.8.10.2 Method invocations From 4271fad60a4db3882f3b75fc07a0d8a91f496765 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Tue, 11 Nov 2025 11:32:38 -0500 Subject: [PATCH 2/7] Add covariant return types feature --- standard/classes.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/standard/classes.md b/standard/classes.md index b02654945..00769cc37 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -2746,6 +2746,8 @@ When an instance method declaration includes an `override` modifier, the method The method overridden by an override declaration is known as the ***overridden base method*** For an override method `M` declared in a class `C`, the overridden base method is determined by examining each base class of `C`, starting with the direct base class of `C` and continuing with each successive direct base class, until in a given base class type at least one accessible method is located which has the same signature as `M` after substitution of type arguments. For the purposes of locating the overridden base method, a method is considered accessible if it is `public`, if it is `protected`, if it is `protected internal`, or if it is either `internal` or `private protected` and declared in the same program as `C`. +For an override method `M` declared in an interface `I`, the overridden base method is determined by examining each direct or indirect base interface of `I`, collecting the set of interfaces declaring an accessible method which has the same signature as `M` after substitution of type arguments. If this set of interfaces has a *most derived type*, to which there is an identity or implicit reference conversion from every type in this set, and that type contains a unique such method declaration, then that is the overridden base method. + The overriding method inherits any *type_parameter_constraints_clause*s of the overridden base method. A compile-time error occurs unless all of the following are true for an override declaration: @@ -2754,8 +2756,11 @@ A compile-time error occurs unless all of the following are true for an override - There is exactly one such overridden base method. This restriction has effect only if the base class type is a constructed type where the substitution of type arguments makes the signature of two methods the same. - The overridden base method is a virtual, abstract, or override method. In other words, the overridden base method cannot be static or non-virtual. - The overridden base method is not a sealed method. -- There is an identity conversion between the return type of the overridden base method and the override method. +- The override method has a return type that is convertible by an identity conversion or (if the method has a value return) an implicit reference conversion to the return type of the overridden base method. +- The override method has a return type that is convertible by an identity conversion or (if the method has a value return a) an implicit reference conversion to the return type of every override of the overridden base method that is declared in a (direct or indirect) base type of the override method. - The override declaration and the overridden base method have the same declared accessibility. In other words, an override declaration cannot change the accessibility of the virtual method. However, if the overridden base method is protected internal and it is declared in a different assembly than the assembly containing the override declaration then the override declaration’s declared accessibility shall be protected. +- The override method's return type is at least as accessible as the override method. + > *Note*: This constraint permits an override method in a `private` class to have a `private` return type. However, it requires a `public` override method in a `public` type to have a `public` return type. *end note* - A *type_parameter_constraints_clause* may only consist of the `class` or `struct` *primary_constraint*s applied to *type_parameter*s which are known according to the inherited constraints to be either reference or value types respectively. Any type of the form `T?` in the overriding method’s signature, where `T` is a type parameter, is interpreted as follows: - If a `class` constraint is added for type parameter `T` then `T?` is a nullable reference type; otherwise - If either there is no added constraint, or a `struct` constraint is added, for the type parameter `T` then `T?` is a nullable value type. @@ -3939,7 +3944,7 @@ A property declaration that includes both the `abstract` and `override` modifier Abstract property declarations are only permitted in abstract classes ([§15.2.2.2](classes.md#15222-abstract-classes)) and interfaces ([§19.4.4](interfaces.md#1944-interface-properties)). The accessors of an inherited virtual property can be overridden in a derived class by including a property declaration that specifies an `override` directive. This is known as an ***overriding property declaration***. An overriding property declaration does not declare a new property. Instead, it simply specializes the implementations of the accessors of an existing virtual property. -The override declaration and the overridden base property are required to have the same declared accessibility. In other words, an override declaration shall not change the accessibility of the base property. However, if the overridden base property is protected internal and it is declared in a different assembly than the assembly containing the override declaration then the override declaration’s declared accessibility shall be protected. If the inherited property has only a single accessor (i.e., if the inherited property is read-only or write-only), the overriding property shall include only that accessor. If the inherited property includes both accessors (i.e., if the inherited property is read-write), the overriding property can include either a single accessor or both accessors. There shall be an identity conversion between the type of the overriding and the inherited property. +The override declaration and the overridden base property are required to have the same declared accessibility. In other words, an override declaration shall not change the accessibility of the base property. However, if the overridden base property is protected internal and it is declared in a different assembly than the assembly containing the override declaration then the override declaration’s declared accessibility shall be protected. The overriding property's type shall be at least as accessible as the overriding property. If the inherited property has only a single accessor (i.e., if the inherited property is read-only or write-only), the overriding property shall include only that accessor. If the inherited property includes both accessors (i.e., if the inherited property is read-write), the overriding property can include either a single accessor or both accessors. There shall be an identity conversion or (if the inherited property is read-only and has a value return) an implicit reference conversion between the type of the overriding and the inherited property. An overriding property declaration may include the `sealed` modifier. Use of this modifier prevents a derived class from further overriding the property. The accessors of a sealed property are also sealed. From dfd45945f09a54fb685953dfc48f43bbecfe4274 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Tue, 11 Nov 2025 11:35:33 -0500 Subject: [PATCH 3/7] Add covariant return types feature --- standard/interfaces.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/standard/interfaces.md b/standard/interfaces.md index 5ed62239f..9416386b7 100644 --- a/standard/interfaces.md +++ b/standard/interfaces.md @@ -1099,10 +1099,10 @@ Members of a constructed interface type are considered to have any type paramete For purposes of interface mapping, a class, interface, or struct member `A` matches an interface member `B` when: -- `A` and `B` are methods, and the name, type, and parameter lists of `A` and `B` are identical. -- `A` and `B` are properties, the name and type of `A` and `B` are identical, and `A` has the same accessors as `B` (`A` is permitted to have additional accessors if it is not an explicit interface member implementation). +- `A` and `B` are methods, and the name, type, and parameter lists of `A` and `B` are identical, and the return type of `A` is convertible to the return type of `B` via an identity of implicit reference conversion to the return type of `B`. +- `A` and `B` are properties, the name of `A` and `B` are identical, `A` has the same accessors as `B` (`A` is permitted to have additional accessors if it is not an explicit interface member implementation), and the type of `A` is convertible to the return type of `B` via an identity conversion or, if `A` is a readonly property, an implicit reference conversion. - `A` and `B` are events, and the name and type of `A` and `B` are identical. -- `A` and `B` are indexers, the type and parameter lists of `A` and `B` are identical, and `A` has the same accessors as `B` (`A` is permitted to have additional accessors if it is not an explicit interface member implementation). +- `A` and `B` are indexers, the parameter lists of `A` and `B` are identical, `A` has the same accessors as `B` (`A` is permitted to have additional accessors if it is not an explicit interface member implementation), and the type of `A` is convertible to the return type of `B` via an identity conversion or, if `A` is a readonly indexer, an implicit reference conversion. Notable implications of the interface-mapping algorithm are: From 854fe83add331b12f851b86fb2b4ffa6db235d7a Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Mon, 2 Feb 2026 13:17:20 -0500 Subject: [PATCH 4/7] proofread existing changes. --- standard/classes.md | 2 +- standard/interfaces.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/standard/classes.md b/standard/classes.md index 00769cc37..820883e45 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -2757,7 +2757,7 @@ A compile-time error occurs unless all of the following are true for an override - The overridden base method is a virtual, abstract, or override method. In other words, the overridden base method cannot be static or non-virtual. - The overridden base method is not a sealed method. - The override method has a return type that is convertible by an identity conversion or (if the method has a value return) an implicit reference conversion to the return type of the overridden base method. -- The override method has a return type that is convertible by an identity conversion or (if the method has a value return a) an implicit reference conversion to the return type of every override of the overridden base method that is declared in a (direct or indirect) base type of the override method. +- The override method has a return type that is convertible by an identity conversion or (if the method has a value return) an implicit reference conversion to the return type of every override of the overridden base method that is declared in a (direct or indirect) base type of the override method. - The override declaration and the overridden base method have the same declared accessibility. In other words, an override declaration cannot change the accessibility of the virtual method. However, if the overridden base method is protected internal and it is declared in a different assembly than the assembly containing the override declaration then the override declaration’s declared accessibility shall be protected. - The override method's return type is at least as accessible as the override method. > *Note*: This constraint permits an override method in a `private` class to have a `private` return type. However, it requires a `public` override method in a `public` type to have a `public` return type. *end note* diff --git a/standard/interfaces.md b/standard/interfaces.md index 9416386b7..20efaa9ea 100644 --- a/standard/interfaces.md +++ b/standard/interfaces.md @@ -1099,7 +1099,7 @@ Members of a constructed interface type are considered to have any type paramete For purposes of interface mapping, a class, interface, or struct member `A` matches an interface member `B` when: -- `A` and `B` are methods, and the name, type, and parameter lists of `A` and `B` are identical, and the return type of `A` is convertible to the return type of `B` via an identity of implicit reference conversion to the return type of `B`. +- `A` and `B` are methods, and the name, type, and parameter lists of `A` and `B` are identical, and the return type of `A` is convertible to the return type of `B` via an identity or implicit reference conversion. - `A` and `B` are properties, the name of `A` and `B` are identical, `A` has the same accessors as `B` (`A` is permitted to have additional accessors if it is not an explicit interface member implementation), and the type of `A` is convertible to the return type of `B` via an identity conversion or, if `A` is a readonly property, an implicit reference conversion. - `A` and `B` are events, and the name and type of `A` and `B` are identical. - `A` and `B` are indexers, the parameter lists of `A` and `B` are identical, `A` has the same accessors as `B` (`A` is permitted to have additional accessors if it is not an explicit interface member implementation), and the type of `A` is convertible to the return type of `B` via an identity conversion or, if `A` is a readonly indexer, an implicit reference conversion. From 120a95ae0fdc5696892e4256b09eaa0942496440 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Mon, 2 Feb 2026 13:44:35 -0500 Subject: [PATCH 5/7] first draft of updates Fill in the sections noted in the description of this PR. --- standard/classes.md | 6 ++++-- standard/expressions.md | 11 +++++++++-- standard/interfaces.md | 4 ++++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/standard/classes.md b/standard/classes.md index 820883e45..edc991753 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -3942,9 +3942,11 @@ An abstract property declaration specifies that the accessors of the property ar A property declaration that includes both the `abstract` and `override` modifiers specifies that the property is abstract and overrides a base property. The accessors of such a property are also abstract. -Abstract property declarations are only permitted in abstract classes ([§15.2.2.2](classes.md#15222-abstract-classes)) and interfaces ([§19.4.4](interfaces.md#1944-interface-properties)). The accessors of an inherited virtual property can be overridden in a derived class by including a property declaration that specifies an `override` directive. This is known as an ***overriding property declaration***. An overriding property declaration does not declare a new property. Instead, it simply specializes the implementations of the accessors of an existing virtual property. +Abstract property declarations are only permitted in abstract classes ([§15.2.2.2](classes.md#15222-abstract-classes)) and interfaces ([§19.4.4](interfaces.md#1944-interface-properties)). The accessors of an inherited virtual property can be overridden in a derived class or interface by including a property declaration that specifies an `override` directive. This is known as an ***overriding property declaration***. An overriding property declaration does not declare a new property. Instead, it simply specializes the implementations of the accessors of an existing virtual property. -The override declaration and the overridden base property are required to have the same declared accessibility. In other words, an override declaration shall not change the accessibility of the base property. However, if the overridden base property is protected internal and it is declared in a different assembly than the assembly containing the override declaration then the override declaration’s declared accessibility shall be protected. The overriding property's type shall be at least as accessible as the overriding property. If the inherited property has only a single accessor (i.e., if the inherited property is read-only or write-only), the overriding property shall include only that accessor. If the inherited property includes both accessors (i.e., if the inherited property is read-write), the overriding property can include either a single accessor or both accessors. There shall be an identity conversion or (if the inherited property is read-only and has a value return) an implicit reference conversion between the type of the overriding and the inherited property. +For an override property `P` declared in an interface `I`, the overridden base property is determined by examining each direct or indirect base interface of `I`, collecting the set of interfaces declaring an accessible property which has the same name as `P`. If this set of interfaces has a *most derived type*, to which there is an identity or implicit reference conversion from every type in this set, and that type contains a unique such property declaration, then that is the overridden base property. + +The override declaration and the overridden base property are required to have the same declared accessibility. In other words, an override declaration shall not change the accessibility of the base property. However, if the overridden base property is protected internal and it is declared in a different assembly than the assembly containing the override declaration then the override declaration’s declared accessibility shall be protected. The overriding property's type shall be at least as accessible as the overriding property. If the inherited property has only a single accessor (i.e., if the inherited property is read-only or write-only), the overriding property shall include only that accessor. If the inherited property includes both accessors (i.e., if the inherited property is read-write), the overriding property can include either a single accessor or both accessors. There shall be an identity conversion or (if the inherited property is read-only and has a value return) an implicit reference conversion between the type of the overriding and the inherited property. For an override property declared in an interface, there shall also be an identity conversion or (if the inherited property is read-only and has a value return) an implicit reference conversion between the type of the overriding property and the type of every override of the overridden base property that is declared in a (direct or indirect) base interface of the overriding property. An overriding property declaration may include the `sealed` modifier. Use of this modifier prevents a derived class from further overriding the property. The accessors of a sealed property are also sealed. diff --git a/standard/expressions.md b/standard/expressions.md index 58b7ce8b3..456feebe0 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -1717,7 +1717,7 @@ The *member_access* is evaluated and classified as follows: - If `E` is a property access, indexer access, variable, or value, the type of which is `T`, and a member lookup ([§12.5](expressions.md#125-member-lookup)) of `I` in `T` with `K` type arguments produces a match, then `E.I` is evaluated and classified as follows: - First, if `E` is a property or indexer access, then the value of the property or indexer access is obtained ([§12.2.2](expressions.md#1222-values-of-expressions)) and E is reclassified as a value. - If `I` identifies one or more methods, then the result is a method group with an associated instance expression of `E`. - - If `I` identifies an instance property, then the result is a property access with an associated instance expression of `E` and an associated type that is the type of the property. If `T` is a class type, the associated type is picked from the first declaration or override of the property found when starting with `T`, and searching through its base classes. If `T` is an interface type, the associated type is picked from the declaration or override of the property found in the most derived of `T` or its direct or indirect base interfaces. It is a compile-time error if no unique such type exists. + - If `I` identifies an instance property, then the result is a property access with an associated instance expression of `E` and an associated type that is the type of the property. If `T` is a class type, the associated type is picked from the first declaration or override of the property found when starting with `T`, and searching through its base classes. If `T` is an interface type, the associated type is picked from the declaration or override of the property found in the most specific ([§19.4.10](interfaces.md#19410-most-specific-implementation)) of `T` or its direct or indirect base interfaces. It is a compile-time error if no unique such type exists. - If `T` is a *class_type* and `I` identifies an instance field of that *class_type*: - If the value of `E` is `null`, then a `System.NullReferenceException` is thrown. - Otherwise, if the field is readonly and the reference occurs outside an instance constructor of the class in which the field is declared, then the result is a value, namely the value of the field `I` in the object referenced by `E`. @@ -1999,7 +1999,7 @@ The result of evaluating an *invocation_expression* is classified as follows: - If the *invocation_expression* invokes a returns-no-value method ([§15.6.1](classes.md#1561-general)) or a returns-no-value delegate, the result is nothing. An expression that is classified as nothing is permitted only in the context of a *statement_expression* ([§13.7](statements.md#137-expression-statements)) or as the body of a *lambda_expression* ([§12.21](expressions.md#1221-anonymous-function-expressions)). Otherwise, a binding-time error occurs. - Otherwise, if the *invocation_expression* invokes a returns-by-ref method ([§15.6.1](classes.md#1561-general)) or a returns-by-ref delegate, the result is a variable with an associated type of the return type of the method or delegate. If the invocation is of an instance method, and the receiver is of a class type `T`, the associated type is picked from the first declaration or override of the method found when starting with `T` and searching through its base classes. -- Otherwise, the *invocation_expression* invokes a returns-by-value method ([§15.6.1](classes.md#1561-general)) or returns-by-value delegate, and the result is a value, with an associated type of the return type of the method or delegate. If the invocation is of an instance method, and the receiver is of a class type `T`, the associated type is picked from the first declaration or override of the method found when starting with `T` and searching through its base classes. If the invocation is of an instance method, and the receiver is of an interface type `T`, the associated type is picked from the declaration or override of the method found in the most derived interface from among `T` and its direct and indirect base interfaces. It is a compile-time error if no unique such type exists. +- Otherwise, the *invocation_expression* invokes a returns-by-value method ([§15.6.1](classes.md#1561-general)) or returns-by-value delegate, and the result is a value, with an associated type of the return type of the method or delegate. If the invocation is of an instance method, and the receiver is of a class type `T`, the associated type is picked from the first declaration or override of the method found when starting with `T` and searching through its base classes. If the invocation is of an instance method, and the receiver is of an interface type `T`, the associated type is picked from the declaration or override of the method found in the most specific ([§19.4.10](interfaces.md#19410-most-specific-implementation)) interface from among `T` and its direct and indirect base interfaces. It is a compile-time error if no unique such type exists. #### 12.8.10.2 Method invocations @@ -2358,6 +2358,13 @@ The binding-time processing of an indexer access of the form `P[A]`, where `P` i - If the indexer access is the target of an assignment then the indexer shall have a set or ref get accessor, otherwise, a binding-time error occurs; - Otherwise the indexer shall have a get or ref get accessor, otherwise a binding-time error occurs. +The result of the indexer access is classified as follows: + +- If the indexer has a ref get accessor, the result is a variable with an associated type of the indexer type. +- Otherwise, the result is a value with an associated type of the indexer type. + +If `T` is a class type, the associated type is picked from the first declaration or override of the indexer found when starting with `T`, and searching through its base classes. If `T` is an interface type, the associated type is picked from the declaration or override of the indexer found in the most specific ([§19.4.10](interfaces.md#19410-most-specific-implementation)) of `T` or its direct or indirect base interfaces. It is a compile-time error if no unique such type exists. + The runtime processing of the indexer access consists of the following steps: - The target *primary_expression* `P` is evaluated. diff --git a/standard/interfaces.md b/standard/interfaces.md index 20efaa9ea..90b1efe6e 100644 --- a/standard/interfaces.md +++ b/standard/interfaces.md @@ -892,6 +892,8 @@ A *type_parameter_constraints_clause* on an explicit interface method implementa For an explicit interface member implementation to be valid, the class, struct, or interface shall name an interface in its base class or base interface list that contains a member whose qualified interface member name, type, number of type parameters, and parameter types exactly match those of the explicit interface member implementation. If an interface function member has a parameter array, the corresponding parameter of an associated explicit interface member implementation is allowed, but not required, to have the `params` modifier. If the interface function member does not have a parameter array then an associated explicit interface member implementation shall not have a parameter array. +For an explicit interface member implementation of a method, property, or indexer that has a return type, there shall be an identity conversion or an implicit reference conversion from the return type of the explicit interface member implementation to the return type of every override of the interface member that is declared in a (direct or indirect) base interface. + > *Example*: Thus, in the following class > > @@ -1104,6 +1106,8 @@ For purposes of interface mapping, a class, interface, or struct member `A` matc - `A` and `B` are events, and the name and type of `A` and `B` are identical. - `A` and `B` are indexers, the parameter lists of `A` and `B` are identical, `A` has the same accessors as `B` (`A` is permitted to have additional accessors if it is not an explicit interface member implementation), and the type of `A` is convertible to the return type of `B` via an identity conversion or, if `A` is a readonly indexer, an implicit reference conversion. +> *Note*: Prior to the introduction of covariant return types, matching required an identity conversion between the return type of `A` and the return type of `B`. Allowing implicit reference conversions changes which member is selected as the implementation when a derived class re-implements an interface with a method that has a more derived return type. *end note* + Notable implications of the interface-mapping algorithm are: - Explicit interface member implementations take precedence over other members in the same class or struct when determining the class or struct member that implements an interface member. From 8c9bd6893e428e5c8c8627a5e4fc0beada07f9b9 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Mon, 2 Feb 2026 14:21:31 -0500 Subject: [PATCH 6/7] Final proofread --- standard/expressions.md | 2 +- standard/interfaces.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/standard/expressions.md b/standard/expressions.md index 456feebe0..b5cc8e892 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -2363,7 +2363,7 @@ The result of the indexer access is classified as follows: - If the indexer has a ref get accessor, the result is a variable with an associated type of the indexer type. - Otherwise, the result is a value with an associated type of the indexer type. -If `T` is a class type, the associated type is picked from the first declaration or override of the indexer found when starting with `T`, and searching through its base classes. If `T` is an interface type, the associated type is picked from the declaration or override of the indexer found in the most specific ([§19.4.10](interfaces.md#19410-most-specific-implementation)) of `T` or its direct or indirect base interfaces. It is a compile-time error if no unique such type exists. +If `T` is a class type, the associated type is picked from the first declaration or override of the indexer found when starting with `T`, and searching through its base classes. If `T` is an interface type, the associated type is picked from the declaration or override of the indexer found in the most specific ([§19.4.10](interfaces.md#19410-most-specific-implementation)) interface among `T` and its direct or indirect base interfaces. It is a compile-time error if no unique such type exists. The runtime processing of the indexer access consists of the following steps: diff --git a/standard/interfaces.md b/standard/interfaces.md index 90b1efe6e..5f44b1b0d 100644 --- a/standard/interfaces.md +++ b/standard/interfaces.md @@ -1102,9 +1102,9 @@ Members of a constructed interface type are considered to have any type paramete For purposes of interface mapping, a class, interface, or struct member `A` matches an interface member `B` when: - `A` and `B` are methods, and the name, type, and parameter lists of `A` and `B` are identical, and the return type of `A` is convertible to the return type of `B` via an identity or implicit reference conversion. -- `A` and `B` are properties, the name of `A` and `B` are identical, `A` has the same accessors as `B` (`A` is permitted to have additional accessors if it is not an explicit interface member implementation), and the type of `A` is convertible to the return type of `B` via an identity conversion or, if `A` is a readonly property, an implicit reference conversion. +- `A` and `B` are properties, the name of `A` and `B` are identical, `A` has the same accessors as `B` (`A` is permitted to have additional accessors if it is not an explicit interface member implementation), and the type of `A` is convertible to the type of `B` via an identity conversion or, if `A` is a readonly property, an implicit reference conversion. - `A` and `B` are events, and the name and type of `A` and `B` are identical. -- `A` and `B` are indexers, the parameter lists of `A` and `B` are identical, `A` has the same accessors as `B` (`A` is permitted to have additional accessors if it is not an explicit interface member implementation), and the type of `A` is convertible to the return type of `B` via an identity conversion or, if `A` is a readonly indexer, an implicit reference conversion. +- `A` and `B` are indexers, the parameter lists of `A` and `B` are identical, `A` has the same accessors as `B` (`A` is permitted to have additional accessors if it is not an explicit interface member implementation), and the type of `A` is convertible to the type of `B` via an identity conversion or, if `A` is a readonly indexer, an implicit reference conversion. > *Note*: Prior to the introduction of covariant return types, matching required an identity conversion between the return type of `A` and the return type of `B`. Allowing implicit reference conversions changes which member is selected as the implementation when a derived class re-implements an interface with a method that has a more derived return type. *end note* From 797f25dda59f183acf7499fb62a4aad00466849c Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Thu, 26 Feb 2026 11:23:48 -0500 Subject: [PATCH 7/7] Update per feedback. Respond to open comments, and perform a review. --- standard/classes.md | 4 +++- standard/expressions.md | 4 ++-- standard/interfaces.md | 10 ++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/standard/classes.md b/standard/classes.md index edc991753..6a88c3ee6 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -3948,7 +3948,9 @@ For an override property `P` declared in an interface `I`, the overridden base p The override declaration and the overridden base property are required to have the same declared accessibility. In other words, an override declaration shall not change the accessibility of the base property. However, if the overridden base property is protected internal and it is declared in a different assembly than the assembly containing the override declaration then the override declaration’s declared accessibility shall be protected. The overriding property's type shall be at least as accessible as the overriding property. If the inherited property has only a single accessor (i.e., if the inherited property is read-only or write-only), the overriding property shall include only that accessor. If the inherited property includes both accessors (i.e., if the inherited property is read-write), the overriding property can include either a single accessor or both accessors. There shall be an identity conversion or (if the inherited property is read-only and has a value return) an implicit reference conversion between the type of the overriding and the inherited property. For an override property declared in an interface, there shall also be an identity conversion or (if the inherited property is read-only and has a value return) an implicit reference conversion between the type of the overriding property and the type of every override of the overridden base property that is declared in a (direct or indirect) base interface of the overriding property. -An overriding property declaration may include the `sealed` modifier. Use of this modifier prevents a derived class from further overriding the property. The accessors of a sealed property are also sealed. +> *Note*: The accessibility constraint on the overriding property's type permits an override property in a `private` class to have a `private` property type. However, it requires a `public` override property in a `public` type to have a `public` property type. *end note* + +An overriding property declaration may include the `sealed` modifier. Use of this modifier prevents a derived class or interface from further overriding the property. The accessors of a sealed property are also sealed. Except for differences in declaration and invocation syntax, virtual, sealed, override, and abstract accessors behave exactly like virtual, sealed, override and abstract methods. Specifically, the rules described in [§15.6.4](classes.md#1564-virtual-methods), [§15.6.5](classes.md#1565-override-methods), [§15.6.6](classes.md#1566-sealed-methods), and [§15.6.7](classes.md#1567-abstract-methods) apply as if accessors were methods of a corresponding form: diff --git a/standard/expressions.md b/standard/expressions.md index b5cc8e892..1e1410988 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -582,7 +582,7 @@ For each argument in an argument list there has to be a corresponding parameter The parameter list used in the following is determined as follows: -- For virtual methods and indexers defined in classes, the parameter list is picked from the first declaration or override of the function member found when starting with the static type of the receiver, and searching through its base classes. For virtual methods and indexers defined in interfaces, the parameter list is picked from the declaration or override of the function member found in the most derived type among those types containing the declaration of override of the function member. It is a compile-time error if no unique such type exists. +- For virtual methods and indexers defined in classes, the parameter list is picked from the first declaration or override of the function member found when starting with the static type of the receiver, and searching through its base classes. For virtual methods and indexers defined in interfaces, the parameter list is picked from the declaration or override of the function member found in the most derived interface among the static type of the receiver and its direct and indirect base interfaces that contains a declaration or override of the function member. It is a compile-time error if no unique such most derived interface exists. - For partial methods, the parameter list of the defining partial method declaration is used. - For all other function members and delegates there is only a single parameter list, which is the one used. @@ -1998,7 +1998,7 @@ The optional *argument_list* ([§12.6.2](expressions.md#1262-argument-lists)) pr The result of evaluating an *invocation_expression* is classified as follows: - If the *invocation_expression* invokes a returns-no-value method ([§15.6.1](classes.md#1561-general)) or a returns-no-value delegate, the result is nothing. An expression that is classified as nothing is permitted only in the context of a *statement_expression* ([§13.7](statements.md#137-expression-statements)) or as the body of a *lambda_expression* ([§12.21](expressions.md#1221-anonymous-function-expressions)). Otherwise, a binding-time error occurs. -- Otherwise, if the *invocation_expression* invokes a returns-by-ref method ([§15.6.1](classes.md#1561-general)) or a returns-by-ref delegate, the result is a variable with an associated type of the return type of the method or delegate. If the invocation is of an instance method, and the receiver is of a class type `T`, the associated type is picked from the first declaration or override of the method found when starting with `T` and searching through its base classes. +- Otherwise, if the *invocation_expression* invokes a returns-by-ref method ([§15.6.1](classes.md#1561-general)) or a returns-by-ref delegate, the result is a variable with an associated type of the return type of the method or delegate. If the invocation is of an instance method, and the receiver is of a class type `T`, the associated type is picked from the first declaration or override of the method found when starting with `T` and searching through its base classes. If the invocation is of an instance method, and the receiver is of an interface type `T`, the associated type is picked from the declaration of the method found in the most specific (§19.4.10) interface from among `T` and its direct and indirect base interfaces. It is a compile-time error if no unique such type exists. - Otherwise, the *invocation_expression* invokes a returns-by-value method ([§15.6.1](classes.md#1561-general)) or returns-by-value delegate, and the result is a value, with an associated type of the return type of the method or delegate. If the invocation is of an instance method, and the receiver is of a class type `T`, the associated type is picked from the first declaration or override of the method found when starting with `T` and searching through its base classes. If the invocation is of an instance method, and the receiver is of an interface type `T`, the associated type is picked from the declaration or override of the method found in the most specific ([§19.4.10](interfaces.md#19410-most-specific-implementation)) interface from among `T` and its direct and indirect base interfaces. It is a compile-time error if no unique such type exists. #### 12.8.10.2 Method invocations diff --git a/standard/interfaces.md b/standard/interfaces.md index 5f44b1b0d..90dbd0d48 100644 --- a/standard/interfaces.md +++ b/standard/interfaces.md @@ -892,7 +892,7 @@ A *type_parameter_constraints_clause* on an explicit interface method implementa For an explicit interface member implementation to be valid, the class, struct, or interface shall name an interface in its base class or base interface list that contains a member whose qualified interface member name, type, number of type parameters, and parameter types exactly match those of the explicit interface member implementation. If an interface function member has a parameter array, the corresponding parameter of an associated explicit interface member implementation is allowed, but not required, to have the `params` modifier. If the interface function member does not have a parameter array then an associated explicit interface member implementation shall not have a parameter array. -For an explicit interface member implementation of a method, property, or indexer that has a return type, there shall be an identity conversion or an implicit reference conversion from the return type of the explicit interface member implementation to the return type of every override of the interface member that is declared in a (direct or indirect) base interface. +For an explicit interface member implementation of a method, property, or indexer that has a return type, there shall be an identity conversion or (if the member has a value return) an implicit reference conversion from the return type of the explicit interface member implementation to the return type of every override of the interface member that is declared in a (direct or indirect) base interface. > *Example*: Thus, in the following class > @@ -1101,12 +1101,10 @@ Members of a constructed interface type are considered to have any type paramete For purposes of interface mapping, a class, interface, or struct member `A` matches an interface member `B` when: -- `A` and `B` are methods, and the name, type, and parameter lists of `A` and `B` are identical, and the return type of `A` is convertible to the return type of `B` via an identity or implicit reference conversion. -- `A` and `B` are properties, the name of `A` and `B` are identical, `A` has the same accessors as `B` (`A` is permitted to have additional accessors if it is not an explicit interface member implementation), and the type of `A` is convertible to the type of `B` via an identity conversion or, if `A` is a readonly property, an implicit reference conversion. +- `A` and `B` are methods, and the name, type, and parameter lists of `A` and `B` are identical. +- `A` and `B` are properties, the name and type of `A` and `B` are identical, and `A` has the same accessors as `B` (`A` is permitted to have additional accessors if it is not an explicit interface member implementation). - `A` and `B` are events, and the name and type of `A` and `B` are identical. -- `A` and `B` are indexers, the parameter lists of `A` and `B` are identical, `A` has the same accessors as `B` (`A` is permitted to have additional accessors if it is not an explicit interface member implementation), and the type of `A` is convertible to the type of `B` via an identity conversion or, if `A` is a readonly indexer, an implicit reference conversion. - -> *Note*: Prior to the introduction of covariant return types, matching required an identity conversion between the return type of `A` and the return type of `B`. Allowing implicit reference conversions changes which member is selected as the implementation when a derived class re-implements an interface with a method that has a more derived return type. *end note* +- `A` and `B` are indexers, the type and parameter lists of `A` and `B` are identical, and `A` has the same accessors as `B` (`A` is permitted to have additional accessors if it is not an explicit interface member implementation). Notable implications of the interface-mapping algorithm are: