From a8a5e5055910efb1b24488ab6effa4f4cc73b602 Mon Sep 17 00:00:00 2001 From: Nigel-Ecma Date: Thu, 6 Jul 2023 16:04:54 +1200 Subject: [PATCH] Changes for ref-valued properties, indexers and methods (This was originally in #837.) The grammar has been extended to be as prescriptive as reasonably possible as befits a language specification[1], this means that former statements such as it being illegal to have a set accessor for a ref-valued property are now covered by the grammar. However the usual verbose description of the grammar remains! The term ref-valued rather than ref-returning is used, a term closer to the language of fields. To distingush the two kinds of properties, which do follow different rules, the corresponding and somewhat ugly term non-ref-valued is used (non-ref-returning would be just as ugly). [1] The grammar used by a compiler may be less restrictive to support more descriptive error messages, that is of course an implementation issue! Fixes #825. --- standard/basic-concepts.md | 2 +- standard/classes.md | 232 +++++++++++++++++++++++++--------- standard/delegates.md | 27 ++-- standard/expressions.md | 4 +- standard/interfaces.md | 32 +++-- standard/lexical-structure.md | 2 +- standard/statements.md | 23 ++-- 7 files changed, 233 insertions(+), 89 deletions(-) diff --git a/standard/basic-concepts.md b/standard/basic-concepts.md index aa2659ee1..1c1b155cc 100644 --- a/standard/basic-concepts.md +++ b/standard/basic-concepts.md @@ -588,7 +588,7 @@ The ***scope*** of a name is the region of program text within which it is possi - The scope of a member declared by a *struct_member_declaration* ([§16.3](structs.md#163-struct-members)) is the *struct_body* in which the declaration occurs. - The scope of a member declared by an *enum_member_declaration* ([§19.4](enums.md#194-enum-members)) is the *enum_body* in which the declaration occurs. -- The scope of a parameter declared in a *method_declaration* ([§15.6](classes.md#156-methods)) is the *method_body* of that *method_declaration*. +- The scope of a parameter declared in a *method_declaration* ([§15.6](classes.md#156-methods)) is the *method_body* or *ref_method_body* of that *method_declaration*. - The scope of a parameter declared in an *indexer_declaration* ([§15.9](classes.md#159-indexers)) is the *indexer_body* of that *indexer_declaration*. - The scope of a parameter declared in an *operator_declaration* ([§15.10](classes.md#1510-operators)) is the *operator_body* of that *operator_declaration*. - The scope of a parameter declared in a *constructor_declaration* ([§15.11](classes.md#1511-instance-constructors)) is the *constructor_initializer* and *block* of that *constructor_declaration*. diff --git a/standard/classes.md b/standard/classes.md index 2527683bf..0c9e59bd9 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -773,7 +773,7 @@ A *class_declaration* creates a new declaration space ([§7.3](basic-concepts.md - The name of a type shall differ from the names of all non-type members declared in the same class. If two or more type declarations share the same fully qualified name, the declarations shall have the `partial` modifier ([§15.2.7](classes.md#1527-partial-declarations)) and these declarations combine to define a single type. -> *Note*: Since the fully qualified name of a type declaration encodes the number of type parameters, two distinct types may share the same name as long as they have different number of type parameters. *end note* +> *Note*: Since the fully qualified name of a type declaration encodes the number of type parameters, two distinct types may share the same name as long as they have different number of type parameters. *end note* - The name of a constant, field, property, or event shall differ from the names of all other members declared in the same class. - The name of a method shall differ from the names of all other non-methods declared in the same class. In addition, the signature ([§7.6](basic-concepts.md#76-signatures-and-overloading)) of a method shall differ from the signatures of all other methods declared in the same class, and two methods declared in the same class shall not have signatures that differ solely by `in`, `out`, and `ref`. @@ -1905,16 +1905,35 @@ A ***method*** is a member that implements a computation or action that can be p ```ANTLR method_declaration - : method_header method_body + : attributes? method_modifiers return_type method_header method_body + | attributes? ref_method_modifiers ref_kind ref_return_type method_header ref_method_body + ; + +method_modifiers + : method_modifier* 'partial'? + ; + +ref_kind + : 'ref' + | 'ref' 'readonly' + ; + +ref_method_modifiers + : ref_method_modifier* ; method_header - : attributes? method_modifier* 'partial'? ('ref' 'readonly'?)? - return_type member_name type_parameter_list? - '(' formal_parameter_list? ')' type_parameter_constraints_clause* + : member_name '(' formal_parameter_list? ')' + | member_name type_parameter_list '(' formal_parameter_list? ')' type_parameter_constraints_clause* ; method_modifier + : ref_method_modifier + | 'async' + | unsafe_modifier // unsafe code support + ; + +ref_method_modifier : 'new' | 'public' | 'protected' @@ -1926,15 +1945,17 @@ method_modifier | 'override' | 'abstract' | 'extern' - | 'async' - | unsafe_modifier // unsafe code support ; return_type - : type + : ref_return_type | 'void' ; +ref_return_type + : type + ; + member_name : identifier | interface_type '.' identifier @@ -1946,6 +1967,12 @@ method_body | '=>' expression ';' | ';' ; + +ref_method_body + : block + | '=>' 'ref' variable_reference ';' + | ';' + ; ``` Grammar notes: @@ -1966,31 +1993,47 @@ A declaration has a valid combination of modifiers if all of the following are t - If the declaration includes the `abstract` modifier, then the declaration does not include any of the following modifiers: `static`, `virtual`, `sealed`, or `extern`. - If the declaration includes the `private` modifier, then the declaration does not include any of the following modifiers: `virtual`, `override`, or `abstract`. - If the declaration includes the `sealed` modifier, then the declaration also includes the `override` modifier. -- If the declaration includes the `partial` modifier, then it does not include any of the following modifiers: new, `public`, `protected`, `internal`, `private`, `virtual`, `sealed`, `override`, `abstract`, or `extern`. +- If the declaration includes the `partial` modifier, then it does not include any of the following modifiers: `new`, `public`, `protected`, `internal`, `private`, `virtual`, `sealed`, `override`, `abstract`, or `extern`. + +Methods are classified according to what, if anything, they return: + +- If `ref` is present, the method is ***returns-by-ref*** and returns a *variable reference*, that is optionally read-only; +- Otherwise, if *return_type* is `void`, the method is ***returns-no-value*** and does not return a value; +- Otherwise, the method is ***returns-by-value*** and returns a value. + +The *return_type* of a returns-by-value or returns-no-value method declaration specifies the type of the result, if any, returned by the method. Only a returns-no-value method may include the `partial` modifier ([§15.6.9](classes.md#1569-partial-methods)). If the declaration includes the `async` modifier then *return_type* shall be `void` or the method returns-by-value and the return type is a *task type* ([§15.15.1](classes.md#15151-general)). -It is a compile-time error to have both `ref` and a *return_type* of `void`. +The *ref_return_type* of a returns-by-ref method declaration specifies the type of the variable referenced by the *variable_reference* returned by the method. -If `ref` is present, the method is ***returns-by-ref***; otherwise, if *return_type* is `void`, the method is ***returns-no-value***; otherwise, the method is ***returns-by-value***. +A generic method is a method whose declaration includes a *type_parameter_list*. This specifies the type parameters for the method. The optional *type_parameter_constraints_clause*s specify the constraints for the type parameters. -The *return_type* of a method declaration specifies the type of the result, if any, returned by the method. A returns-no-value method does not return a value. A returns-by-ref method returns a *variable_reference* ([§9.5](variables.md#95-variable-references)), that is optionally read-only. A returns-by-value method returns a value. If the declaration includes the `partial` modifier, then *return_type* shall be `void` ([§15.6.9](classes.md#1569-partial-methods)). If the declaration includes the `async` modifier then *return_type* shall be `void` or the method returns-by-value and the return type is a *task type* ([§15.15.1](classes.md#15151-general)). +A generic *method_declaration* for an explicit interface member implementation shall not have any *type_parameter_constraints_clause*s; the declaration inherits any constraints from the constraints on the interface method. -A generic method is a method whose declaration includes a *type_parameter_list*. This specifies the type parameters for the method. The optional *type_parameter_constraints_clause*s specify the constraints for the type parameters. A *method_declaration* shall not have *type_parameter_constraints_clauses* unless it also has a *type_parameter_list*. A *method_declaration* for an explicit interface member implementation shall not have any *type_parameter_constraints_clause*s. A generic *method_declaration* for an explicit interface member implementation inherits any constraints from the constraints on the interface method. Similarly, a method declaration with the `override` modifier shall not have any *type_parameter_constraints_clause*s and the constraints of the method’s type parameters are inherited from the virtual method being overridden.The *member_name* specifies the name of the method. Unless the method is an explicit interface member implementation ([§18.6.2](interfaces.md#1862-explicit-interface-member-implementations)), the *member_name* is simply an *identifier*. For an explicit interface member implementation, the *member_name* consists of an *interface_type* followed by a “`.`” and an *identifier*. In this case, the declaration shall include no modifiers other than (possibly) `extern` or `async`. +Similarly, a method declaration with the `override` modifier shall not have any *type_parameter_constraints_clause*s and the constraints of the method’s type parameters are inherited from the virtual method being overridden. + +The *member_name* specifies the name of the method. Unless the method is an explicit interface member implementation ([§18.6.2](interfaces.md#1862-explicit-interface-member-implementations)), the *member_name* is simply an *identifier*. + +For an explicit interface member implementation, the *member_name* consists of an *interface_type* followed by a “`.`” and an *identifier*. In this case, the declaration shall include no modifiers other than (possibly) `extern` or `async`. The optional *formal_parameter_list* specifies the parameters of the method ([§15.6.2](classes.md#1562-method-parameters)). -The *return_type* and each of the types referenced in the *formal_parameter_list* of a method shall be at least as accessible as the method itself ([§7.5.5](basic-concepts.md#755-accessibility-constraints)). +The *return_type* or *ref_return_type*, and each of the types referenced in the *formal_parameter_list* of a method, shall be at least as accessible as the method itself ([§7.5.5](basic-concepts.md#755-accessibility-constraints)). -The *method_body* is either a semicolon, a ***block body*** or an ***expression body***. A block body consists of a *block*, which specifies the statements to execute when the method is invoked. An expression body consists of `=>`, followed by a *null_conditional_invocation_expression* or *expression*, followed by a semicolon, and denotes a single expression to perform when the method is invoked. +The *method_body* of a returns-by-value or returns-no-value method is either a semicolon, a ***block body*** or an ***expression body***. A block body consists of a *block*, which specifies the statements to execute when the method is invoked. An expression body consists of `=>`, followed by a *null_conditional_invocation_expression* or *expression*, and a semicolon, and denotes a single expression to perform when the method is invoked. For abstract and extern methods, the *method_body* consists simply of a semicolon. For partial methods the *method_body* may consist of either a semicolon, a block body or an expression body. For all other methods, the *method_body* is either a block body or an expression body. If the *method_body* consists of a semicolon, the declaration shall not include the `async` modifier. +The *ref_method_body* of a returns-by-ref method is either a semicolon, a ***block body*** or an ***expression body***. A block body consists of a *block*, which specifies the statements to execute when the method is invoked. An expression body consists of `=>`, followed by `ref`, a *variable_reference*, and a semicolon, and denotes a single *variable_reference* to evaluate when the method is invoked. + +For abstract and extern methods, the *ref_method_body* consists simply of a semicolon; for all other methods, the *ref_method_body* is either a block body or an expression body. + The name, the number of type parameters, and the formal parameter list of a method define the signature ([§7.6](basic-concepts.md#76-signatures-and-overloading)) of the method. Specifically, the signature of a method consists of its name, the number of its type parameters, and the number, *parameter_mode_modifier*s ([§15.6.2.1](classes.md#15621-general)), and types of its formal parameters. The return type is not part of a method’s signature, nor are the names of the formal parameters, the names of the type parameters, or the constraints. When a formal parameter type references a type parameter of the method, the ordinal position of the type parameter (not the name of the type parameter) is used for type equivalence. The name of a method shall differ from the names of all other non-methods declared in the same class. In addition, the signature of a method shall differ from the signatures of all other methods declared in the same class, and two methods declared in the same class may not have signatures that differ solely by `in`, `out`, and `ref`. -The method’s *type_parameter*s are in scope throughout the *method_declaration*, and can be used to form types throughout that scope in *return_type*, *method_body*, and *type_parameter_constraints_clause*s but not in *attributes*. +The method’s *type_parameter*s are in scope throughout the *method_declaration*, and can be used to form types throughout that scope in *return_type* or *ref_return_type*, *method_body* or *ref_method_body*, and *type_parameter_constraints_clause*s but not in *attributes*. All formal parameters and type parameters shall have different names. @@ -2697,7 +2740,7 @@ When an instance method declaration includes a `sealed` modifier, that method is When an instance method declaration includes an `abstract` modifier, that method is said to be an ***abstract method***. Although an abstract method is implicitly also a virtual method, it cannot have the modifier `virtual`. -An abstract method declaration introduces a new virtual method but does not provide an implementation of that method. Instead, non-abstract derived classes are required to provide their own implementation by overriding that method. Because an abstract method provides no actual implementation, the *method_body* of an abstract method simply consists of a semicolon. +An abstract method declaration introduces a new virtual method but does not provide an implementation of that method. Instead, non-abstract derived classes are required to provide their own implementation by overriding that method. Because an abstract method provides no actual implementation, the method body of an abstract method simply consists of a semicolon. Abstract method declarations are only permitted in abstract classes ([§15.2.2.2](classes.md#15222-abstract-classes)). @@ -2775,7 +2818,7 @@ An abstract method declaration is permitted to override a virtual method. This a ### 15.6.8 External methods -When a method declaration includes an `extern` modifier, the method is said to be an ***external method***. External methods are implemented externally, typically using a language other than C#. Because an external method declaration provides no actual implementation, the *method_body* of an external method simply consists of a semicolon. An external method shall not be generic. +When a method declaration includes an `extern` modifier, the method is said to be an ***external method***. External methods are implemented externally, typically using a language other than C#. Because an external method declaration provides no actual implementation, the method body of an external method simply consists of a semicolon. An external method shall not be generic. The mechanism by which linkage to an external method is achieved, is implementation-defined. @@ -3015,7 +3058,7 @@ An extension method is a regular static method. In addition, where its enclosing ### 15.6.11 Method body -The *method_body* of a method declaration consists of either a block body, an expression body or a semicolon. +The method body of a method declaration consists of either a block body, an expression body or a semicolon. Abstract and external method declarations do not provide a method implementation, so their method bodies simply consist of a semicolon. For any other method, the method body is a block ([§13.3](statements.md#133-blocks)) that contains the statements to execute when that method is invoked. @@ -3074,8 +3117,8 @@ Properties are declared using *property_declaration*s: ```ANTLR property_declaration - : attributes? property_modifier* ('ref' 'readonly'?)? type - member_name property_body + : attributes? property_modifier* type member_name property_body + | attributes? property_modifier* ref_kind type member_name ref_property_body ; property_modifier @@ -3101,27 +3144,39 @@ property_body property_initializer : '=' variable_initializer ';' ; + +ref_property_body + : '{' ref_get_accessor_declaration '}' + | '=>' 'ref' variable_reference ';' + ; ``` *unsafe_modifier* ([§23.2](unsafe-code.md#232-unsafe-contexts)) is only available in unsafe code ([§23](unsafe-code.md#23-unsafe-code)). +There are two kinds of *property_declaration*: + +- The first declares a non-ref-valued property. Its value has type *type*. This kind of property may be readable and/or writeable. +- The second declares a ref-valued property. Its value is a *variable_reference* ([§9.5](variables.md#95-variable-references)), that may be `readonly`, to a variable of type *type*. This kind of property is only readable. + A *property_declaration* may include a set of *attributes* ([§22](attributes.md#22-attributes)) and any one of the permitted kinds of declared accessibility ([§15.3.6](classes.md#1536-access-modifiers)), the `new` ([§15.3.5](classes.md#1535-the-new-modifier)), `static` ([§15.7.2](classes.md#1572-static-and-instance-properties)), `virtual` ([§15.6.4](classes.md#1564-virtual-methods), [§15.7.6](classes.md#1576-virtual-sealed-override-and-abstract-accessors)), `override` ([§15.6.5](classes.md#1565-override-methods), [§15.7.6](classes.md#1576-virtual-sealed-override-and-abstract-accessors)), `sealed` ([§15.6.6](classes.md#1566-sealed-methods)), `abstract` ([§15.6.7](classes.md#1567-abstract-methods), [§15.7.6](classes.md#1576-virtual-sealed-override-and-abstract-accessors)), and `extern` ([§15.6.8](classes.md#1568-external-methods)) modifiers. Property declarations are subject to the same rules as method declarations ([§15.6](classes.md#156-methods)) with regard to valid combinations of modifiers. -The *type* of a property declaration specifies the type of the property introduced by the declaration. If the `ref` modifier is present, the expression returned is a *variable_reference* ([§9.4](variables.md#94-definite-assignment)), that is optionally read-only. The *member_name* ([§15.6.1](classes.md#1561-general)) specifies the name of the property. Unless the property is an explicit interface member implementation, the *member_name* is simply an *identifier*. For an explicit interface member implementation ([§18.6.2](interfaces.md#1862-explicit-interface-member-implementations)), the *member_name* consists of an *interface_type* followed by a “`.`” and an *identifier*. - -A ref-returning property shall not have a `set` accessor. +The *member_name* ([§15.6.1](classes.md#1561-general)) specifies the name of the property. Unless the property is an explicit interface member implementation, the *member_name* is simply an *identifier*. For an explicit interface member implementation ([§18.6.2](interfaces.md#1862-explicit-interface-member-implementations)), the *member_name* consists of an *interface_type* followed by a “`.`” and an *identifier*. The *type* of a property shall be at least as accessible as the property itself ([§7.5.5](basic-concepts.md#755-accessibility-constraints)). -A *property_body* may either consist of an ***accessor body*** or an expression body. In an accessor body, *accessor_declarations*, which shall be enclosed in “`{`” and “`}`” tokens, declare the accessors ([§15.7.3](classes.md#1573-accessors)) of the property. The accessors specify the executable statements associated with reading and writing the property. +A *property_body* may either consist of a ***statement body*** or an ***expression body***. In a statement body, *accessor_declarations*, which shall be enclosed in “`{`” and “`}`” tokens, declare the accessors ([§15.7.3](classes.md#1573-accessors)) of the property. The accessors specify the executable statements associated with reading and writing the property. -An expression body consisting of `=>` followed by an *expression* `E` and a semicolon is exactly equivalent to the statement body `{ get { return E; } }`, and can therefore only be used to specify read-only properties where the result of the get accessor is given by a single expression. +In a *property_body* an expression body consisting of `=>` followed by an *expression* `E` and a semicolon is exactly equivalent to the statement body `{ get { return E; } }`, and can therefore only be used to specify read-only properties where the result of the get accessor is given by a single expression. A *property_initializer* may only be given for an automatically implemented property ([§15.7.4](classes.md#1574-automatically-implemented-properties)), and causes the initialization of the underlying field of such properties with the value given by the *expression*. -> *Note*: Even though the syntax for accessing a property is the same as that for a field, a property is not classified as a variable. Thus, it is not possible to pass a property as an `in`, `out`, or `ref` argument unless the property itself returns a reference ([§9.7](variables.md#97-reference-variables-and-returns)). *end note* +A *ref_property_body* may either consist of a statement body or an expression body. In a statement body a *get_accessor_declaration* declares the get accessor ([§15.7.3](classes.md#1573-accessors)) of the property. The accessor specifies the executable statements associated with reading the property. + +In a *ref_property_body* an expression body consisting of `=>` followed by `ref`, a *variable_reference* `V` and a semicolon is exactly equivalent to the statement body `{ get { return ref V; } }`. + +> *Note*: Even though the syntax for accessing a property is the same as that for a field, a property is not classified as a variable. Thus, it is not possible to pass a property as an `in`, `out`, or `ref` argument unless the property is ref-valued and therefore returns a variable reference ([§9.7](variables.md#97-reference-variables-and-returns)). *end note* When a property declaration includes an `extern` modifier, the property is said to be an ***external property***. Because an external property declaration provides no actual implementation, each of its *accessor_declarations* consists of a semicolon. @@ -3137,7 +3192,9 @@ The differences between static and instance members are discussed further in [§ ### 15.7.3 Accessors -The *accessor_declarations* of a property specify the executable statements associated with reading and writing that property. +*Note*: This clause applies to both properties ([§15.7](classes.md#157-properties)) and indexers ([§15.9](classes.md#159-indexers)). The clause is written in terms of properties, when reading for indexers substitute indexer/indexers for property/properties and consult the list of differences between properties and indexers given in [§15.9.2](classes.md#1592-indexer-and-property-differences). *end note* + +The *accessor_declarations* of a property specify the executable statements associated with writing and/or reading that property. ```ANTLR accessor_declarations @@ -3168,9 +3225,21 @@ accessor_body | '=>' expression ';' | ';' ; + +ref_get_accessor_declaration + : attributes? accessor_modifier? 'get' ref_accessor_body + ; + +ref_accessor_body + : block + | '=>' 'ref' variable_reference ';' + | ';' + ; ``` -The accessor declarations consist of a *get_accessor_declaration*, a *set_accessor_declaration*, or both. Each accessor declaration consists of optional attributes, an optional *accessor_modifier*, the token `get` or `set`, followed by an *accessor_body*. +The *accessor_declarations* consist of a *get_accessor_declaration*, a *set_accessor_declaration*, or both. Each accessor declaration consists of optional attributes, an optional *accessor_modifier*, the token `get` or `set`, followed by an *accessor_body*. + +For a ref-valued property the *ref_get_accessor_declaration* consists optional attributes, an optional *accessor_modifier*, the token `get`, followed by an *ref_accessor_body*. The use of *accessor_modifier*s is governed by the following restrictions: @@ -3184,12 +3253,44 @@ The use of *accessor_modifier*s is governed by the following restrictions: - If the property or indexer has a declared accessibility of `private protected`, the accessibility declared by *accessor_modifier* shall be `private`. - If the property or indexer has a declared accessibility of `private`, no *accessor_modifier* may be used. -For `abstract` and `extern` properties, the *accessor_body* for each accessor specified is simply a semicolon. A non-abstract, non-extern property may also have the *accessor_body* for all accessors specified be a semicolon, in which case it is an ***automatically implemented property*** ([§15.7.4](classes.md#1574-automatically-implemented-properties)). An automatically implemented property shall have at least a get accessor. For the accessors of any other non-abstract, non-extern property, the *accessor_body* is either +For `abstract` and `extern` non-ref-valued properties, any *accessor_body* for each accessor specified is simply a semicolon. A non-abstract, non-extern property, but not an indexer, may also have the *accessor_body* for all accessors specified be a semicolon, in which case it is an ***automatically implemented property*** ([§15.7.4](classes.md#1574-automatically-implemented-properties)). An automatically implemented property shall have at least a get accessor. For the accessors of any other non-abstract, non-extern property, the *accessor_body* is either: - a *block* that specifies the statements to be executed when the corresponding accessor is invoked; or - an expression body, which consists of `=>` followed by an *expression* and a semicolon, and denotes a single expression to be executed when the corresponding accessor is invoked. -A get accessor corresponds to a parameterless method with a return value of the property type. Except as the target of an assignment, when a property is referenced in an expression, the get accessor of the property is invoked to compute the value of the property ([§12.2.2](expressions.md#1222-values-of-expressions)). The body of a get accessor shall conform to the rules for value-returning methods described in [§15.6.11](classes.md#15611-method-body). In particular, all `return` statements in the body of a get accessor shall specify an expression that is implicitly convertible to the property type. Furthermore, the endpoint of a get accessor shall not be reachable. +For `abstract` and `extern` ref-valued properties the *ref_accessor_body* is simply a semicolon. For the accessor of any other non-abstract, non-extern property, the *ref_accessor_body* is either: + +- a *block* that specifies the statements to be executed when the get accessor is invoked; or +- an expression body, which consists of `=>` followed by `ref`, a *variable_reference* and a semicolon. The variable reference is evaluated when the get accessor is invoked. + +A get accessor for a non-ref-valued property corresponds to a parameterless method with a return value of the property type. Except as the target of an assignment, when such a property is referenced in an expression its get accessor is invoked to compute the value of the property ([§12.2.2](expressions.md#1222-values-of-expressions)). + +The body of a get accessor for a non-ref-valued property shall conform to the rules for value-returning methods described in [§15.6.11](classes.md#15611-method-body). In particular, all `return` statements in the body of a get accessor shall specify an expression that is implicitly convertible to the property type. Furthermore, the endpoint of a get accessor shall not be reachable. + +A get accessor for a ref-valued property corresponds to a parameterless method with a return value of a *variable_reference* to a variable of the property type. When such a property is referenced in an expression its get accessor is invoked to compute the *variable_reference* value of the property. That *variable reference*, like any other, is then used to read or, for non-readonly *variable_reference*s, write the referenced variable as required by the context. + +> *Example*: The following example illustrates a ref-valued property as the target of an assignment: +> +> ```csharp +> class Program +> { +> static int field; +> static ref int Property => ref field; +> +> static void Main() +> { +> field = 10; +> Console.WriteLine(Property); // Prints 10 +> Property = 20; // This invokes the getter, then assigns via the +> // resulting variable reference +> Console.WriteLine(field); // Prints 20 +> } +> } +> ``` +> +> *end example* + +The body of a get accessor for a ref-valued property shall conform to the rules for ref-valued methods described in [§15.6.11](classes.md#15611-method-body). A set accessor corresponds to a method with a single value parameter of the property type and a `void` return type. The implicit parameter of a set accessor is always named `value`. When a property is referenced as the target of an assignment ([§12.21](expressions.md#1221-assignment-operators)), or as the operand of `++` or `–-` ([§12.8.15](expressions.md#12815-postfix-increment-and-decrement-operators), [§12.9.6](expressions.md#1296-prefix-increment-and-decrement-operators)), the set accessor is invoked with an argument that provides the new value ([§12.21.2](expressions.md#12212-simple-assignment)). The body of a set accessor shall conform to the rules for `void` methods described in [§15.6.11](classes.md#15611-method-body). In particular, return statements in the set accessor body are not permitted to specify an expression. Since a set accessor implicitly has a parameter named `value`, it is a compile-time error for a local variable or constant declaration in a set accessor to have that name. @@ -3447,7 +3548,7 @@ Properties can be used to delay initialization of a resource until the moment it ### 15.7.4 Automatically implemented properties -An automatically implemented property (or auto-property for short), is a non-abstract, non-extern property with semicolon-only accessor bodies. Auto-properties shall have a get accessor and may optionally have a set accessor. +An automatically implemented property (or auto-property for short), is a non-abstract, non-extern, non-ref-valued property with semicolon-only accessor bodies. Auto-properties shall have a get accessor and may optionally have a set accessor. When a property is specified as an automatically implemented property, a hidden backing field is automatically available for the property, and the accessors are implemented to read from and write to that backing field. The hidden backing field is inaccessible, it can be read and written only through the automatically implemented property accessors, even within the containing type. If the auto-property has no set accessor, the backing field is considered `readonly` ([§15.5.3](classes.md#1553-readonly-fields)). Just like a `readonly` field, a read-only auto-property may also be assigned to in the body of a constructor of the enclosing class. Such an assignment assigns directly to the read-only backing field of the property. @@ -3561,7 +3662,7 @@ If an accessor has an *accessor_modifier*, the accessibility domain ([§7.5.3](b The presence of an *accessor_modifier* never affects member lookup ([§12.5](expressions.md#125-member-lookup)) or overload resolution ([§12.6.4](expressions.md#1264-overload-resolution)). The modifiers on the property or indexer always determine which property or indexer is bound to, regardless of the context of the access. -Once a particular property or indexer has been selected, the accessibility domains of the specific accessors involved are used to determine if that usage is valid: +Once a particular non-ref-valued property or non-ref-valued indexer has been selected, the accessibility domains of the specific accessors involved are used to determine if that usage is valid: - If the usage is as a value ([§12.2.2](expressions.md#1222-values-of-expressions)), the get accessor shall exist and be accessible. - If the usage is as the target of a simple assignment ([§12.21.2](expressions.md#12212-simple-assignment)), the set accessor shall exist and be accessible. @@ -3619,6 +3720,8 @@ Once a particular property or indexer has been selected, the accessibility domai > > *end example* +Once a particular ref-valued property or ref-valued indexer has been selected; whether the usage is as a value, the target of a simple assignment, or the target of a compound assignment; the accessibility domain of the get accessor involved is used to determine if that usage is valid. + An accessor that is used to implement an interface shall not have an *accessor_modifier*. If only one accessor is used to implement an interface, the other accessor may be declared with an *accessor_modifier*: > *Example*: @@ -3644,6 +3747,8 @@ An accessor that is used to implement an interface shall not have an *accessor_m ### 15.7.6 Virtual, sealed, override, and abstract accessors +*Note*: This clause applies to both properties ([§15.7](classes.md#157-properties)) and indexers ([§15.9](classes.md#159-indexers)). The clause is written in terms of properties, when reading for indexers substitute indexer/indexers for property/properties and consult the list of differences between properties and indexers given in [§15.9.2](classes.md#1592-indexer-and-property-differences). *end note* + A virtual property declaration specifies that the accessors of the property are virtual. The `virtual` modifier applies to all non-private accessors of a property. When an accessor of a virtual property has the private *accessor_modifier*, the `private` accessor is implicitly not virtual. An abstract property declaration specifies that the accessors of the property are virtual, but does not provide an actual implementation of the accessors. Instead, non-abstract derived classes are required to provide their own implementation for the accessors by overriding the property. Because an accessor for an abstract property declaration provides no actual implementation, its *accessor_body* simply consists of a semicolon. An abstract property shall not have a `private` accessor. @@ -4030,11 +4135,14 @@ Except for differences in declaration and invocation syntax, virtual, sealed, ov ## 15.9 Indexers +### 15.9.1 General + An ***indexer*** is a member that enables an object to be indexed in the same way as an array. Indexers are declared using *indexer_declaration*s: ```ANTLR indexer_declaration : attributes? indexer_modifier* indexer_declarator indexer_body + | attributes? indexer_modifier* ref_kind indexer_declarator ref_indexer_body ; indexer_modifier @@ -4052,24 +4160,32 @@ indexer_modifier ; indexer_declarator - : ('ref' 'readonly'?)? type 'this' '[' formal_parameter_list ']' - | ('ref' 'readonly'?)? type interface_type '.' 'this' '[' formal_parameter_list ']' + : type 'this' '[' formal_parameter_list ']' + | type interface_type '.' 'this' '[' formal_parameter_list ']' ; indexer_body : '{' accessor_declarations '}' | '=>' expression ';' ; + +ref_indexer_body + : '{' ref_get_accessor_declaration '}' + | '=>' 'ref' variable_reference ';' + ; ``` *unsafe_modifier* ([§23.2](unsafe-code.md#232-unsafe-contexts)) is only available in unsafe code ([§23](unsafe-code.md#23-unsafe-code)). +There are two kinds of *indexer_declaration*: + +- The first declares a non-ref-valued indexer. Its value has type *type*. This kind of indexer may be readable and/or writeable. +- The second declares a ref-valued indexer. Its value is a *variable_reference* ([§9.5](variables.md#95-variable-references)), that may be `readonly`, to a variable of type *type*. This kind of indexer is only readable. + An *indexer_declaration* may include a set of *attributes* ([§22](attributes.md#22-attributes)) and any one of the permitted kinds of declared accessibility ([§15.3.6](classes.md#1536-access-modifiers)), the `new` ([§15.3.5](classes.md#1535-the-new-modifier)), `virtual` ([§15.6.4](classes.md#1564-virtual-methods)), `override` ([§15.6.5](classes.md#1565-override-methods)), `sealed` ([§15.6.6](classes.md#1566-sealed-methods)), `abstract` ([§15.6.7](classes.md#1567-abstract-methods)), and `extern` ([§15.6.8](classes.md#1568-external-methods)) modifiers. Indexer declarations are subject to the same rules as method declarations ([§15.6](classes.md#156-methods)) with regard to valid combinations of modifiers, with the one exception being that the `static` modifier is not permitted on an indexer declaration. -The modifiers `virtual`, `override`, and `abstract` are mutually exclusive except in one case. The `abstract` and `override` modifiers may be used together so that an abstract indexer can override a virtual one. - The *type* of an indexer declaration specifies the element type of the indexer introduced by the declaration. > *Note*: As indexers are designed to be used in array element-like contexts, the term *element type* as defined for an array is also used with an indexer. *end note* @@ -4082,35 +4198,20 @@ The *formal_parameter_list* specifies the parameters of the indexer. The formal The *type* of an indexer and each of the types referenced in the *formal_parameter_list* shall be at least as accessible as the indexer itself ([§7.5.5](basic-concepts.md#755-accessibility-constraints)). -An *indexer_body* may either consist of an accessor body ([§15.7.1](classes.md#1571-general)) or an expression body ([§15.6.1](classes.md#1561-general)). In an accessor body, *accessor_declarations*, which shall be enclosed in “`{`” and “`}`” tokens, declare the accessors ([§15.7.3](classes.md#1573-accessors)) of the indexer. The accessors specify the executable statements associated with reading and writing indexer elements. +An *indexer_body* may either consist of a statement body ([§15.7.1](classes.md#1571-general)) or an expression body ([§15.6.1](classes.md#1561-general)). In a statement body, *accessor_declarations*, which shall be enclosed in “`{`” and “`}`” tokens, declare the accessors ([§15.7.3](classes.md#1573-accessors)) of the indexer. The accessors specify the executable statements associated with reading and writing indexer elements. -Based on the presence or absence of get and set accessors, an indexer is classified as follows: +In a *indexer_body* an expression body consisting of “`=>`” followed by an expression `E` and a semicolon is exactly equivalent to the statement body `{ get { return E; } }`, and can therefore only be used to specify read-only indexers where the result of the get accessor is given by a single expression. -- An indexer that includes both a get accessor and a set accessor is said to be a ***read-write indexer***. -- An indexer that has only a get accessor is said to be a ***read-only indexer***. It is a compile-time error for a read-only indexer to be the target of an assignment. -- An indexer that has only a set accessor is said to be a ***write-only indexer***. Except as the target of an assignment, it is a compile-time error to reference a write-only indexer in an expression. +A *ref_indexer_body* may either consist of a statement body or an expression body. In a statement body a *get_accessor_declaration* declares the get accessor ([§15.7.3](classes.md#1573-accessors)) of the property. The accessor specifies the executable statements associated with reading the property. -An expression body consisting of “`=>`” followed by an expression `E` and a semicolon is exactly equivalent to the block body `{ get { return E; } }`, and can therefore only be used to specify read-only indexers where the result of the get accessor is given by a single expression. +In a *ref_indexer_body* an expression body consisting of `=>` followed by `ref`, a *variable_reference* `V` and a semicolon is exactly equivalent to the statement body `{ get { return ref V; } }`. -> *Note*: Even though the syntax for accessing an indexer element is the same as that for an array element, an indexer element is not classified as a variable. Thus, it is not possible to pass an indexer element as an `in`, `out`, or `ref` argument unless the indexer itself returns a reference ([§9.7](variables.md#97-reference-variables-and-returns)). *end note* +> *Note*: Even though the syntax for accessing an indexer element is the same as that for an array element, an indexer element is not classified as a variable. Thus, it is not possible to pass an indexer element as an `in`, `out`, or `ref` argument unless the indexer is ref-valued and therefore returns a reference ([§9.7](variables.md#97-reference-variables-and-returns)). *end note* The *formal_parameter_list* of an indexer defines the signature ([§7.6](basic-concepts.md#76-signatures-and-overloading)) of the indexer. Specifically, the signature of an indexer consists of the number and types of its formal parameters. The element type and names of the formal parameters are not part of an indexer’s signature. The signature of an indexer shall differ from the signatures of all other indexers declared in the same class. -Indexers and properties are very similar in concept, but differ in the following ways: - -- A property is identified by its name, whereas an indexer is identified by its signature. -- A property is accessed through a *simple_name* ([§12.8.4](expressions.md#1284-simple-names)) or a *member_access* ([§12.8.7](expressions.md#1287-member-access)), whereas an indexer element is accessed through an *element_access* ([§12.8.11.3](expressions.md#128113-indexer-access)). -- A property can be a static member, whereas an indexer is always an instance member. -- A get accessor of a property corresponds to a method with no parameters, whereas a get accessor of an indexer corresponds to a method with the same formal parameter list as the indexer. -- A set accessor of a property corresponds to a method with a single parameter named `value`, whereas a set accessor of an indexer corresponds to a method with the same formal parameter list as the indexer, plus an additional parameter named `value`. -- It is a compile-time error for an indexer accessor to declare a local variable or local constant with the same name as an indexer parameter. -- In an overriding property declaration, the inherited property is accessed using the syntax `base.P`, where `P` is the property name. In an overriding indexer declaration, the inherited indexer is accessed using the syntax `base[E]`, where `E` is a comma-separated list of expressions. -- There is no concept of an “automatically implemented indexer”. It is an error to have a non-abstract, non-external indexer with semicolon accessors. - -Aside from these differences, all rules defined in [§15.7.3](classes.md#1573-accessors) and [§15.7.4](classes.md#1574-automatically-implemented-properties) apply to indexer accessors as well as to property accessors. - When an indexer declaration includes an `extern` modifier, the indexer is said to be an ***external indexer***. Because an external indexer declaration provides no actual implementation, each of its *accessor_declarations* consists of a semicolon. > *Example*: The example below declares a `BitArray` class that implements an indexer for accessing the individual bits in the bit array. @@ -4245,6 +4346,23 @@ When an indexer declaration includes an `extern` modifier, the indexer is said t > > *end example* +### 15.9.2 Indexer and Property Differences + +Indexers and properties are very similar in concept, but differ in the following ways: + +- A property is identified by its name, whereas an indexer is identified by its signature. +- A property is accessed through a *simple_name* ([§12.8.4](expressions.md#1284-simple-names)) or a *member_access* ([§12.8.7](expressions.md#1287-member-access)), whereas an indexer element is accessed through an *element_access* ([§12.8.11.3](expressions.md#128113-indexer-access)). +- A property can be a static member, whereas an indexer is always an instance member. +- A get accessor of a property corresponds to a method with no parameters, whereas a get accessor of an indexer corresponds to a method with the same formal parameter list as the indexer. +- A set accessor of a property corresponds to a method with a single parameter named `value`, whereas a set accessor of an indexer corresponds to a method with the same formal parameter list as the indexer, plus an additional parameter named `value`. +- It is a compile-time error for an indexer accessor to declare a local variable or local constant with the same name as an indexer parameter. +- In an overriding property declaration, the inherited property is accessed using the syntax `base.P`, where `P` is the property name. In an overriding indexer declaration, the inherited indexer is accessed using the syntax `base[E]`, where `E` is a comma-separated list of expressions. +- There is no concept of an “automatically implemented indexer”. It is an error to have a non-abstract, non-external indexer with semicolon accessors. + +Aside from these differences, all rules defined in [§15.7.3](classes.md#1573-accessors), [§15.7.5](classes.md#1575-accessibility) and [§15.7.6](classes.md#1576-virtual-sealed-override-and-abstract-accessors) apply to indexer accessors as well as to property accessors. + +*Note*: This replacing of property/properties with indexer/indexers when reading [§15.7.3](classes.md#1573-accessors), [§15.7.5](classes.md#1575-accessibility) and [§15.7.6](classes.md#1576-virtual-sealed-override-and-abstract-accessors) applies to defined terms as well. For example *read-write property* becomes *read-write-indexer*. *end note* + ## 15.10 Operators ### 15.10.1 General diff --git a/standard/delegates.md b/standard/delegates.md index 7946643d7..54b568f2c 100644 --- a/standard/delegates.md +++ b/standard/delegates.md @@ -12,17 +12,26 @@ A *delegate_declaration* is a *type_declaration* ([§14.7](namespaces.md#147-typ ```ANTLR delegate_declaration - : attributes? delegate_modifier* 'delegate' ('ref' 'readonly'?)? return_type identifier variant_type_parameter_list? - '(' formal_parameter_list? ')' type_parameter_constraints_clause* ';' + : attributes? delegate_modifier* 'delegate' return_type delegate_header + | attributes? ref_delegate_modifier* 'delegate' ref_kind ref_return_type delegate_header + ; + +delegate_header + : identifier '(' formal_parameter_list? ')' ';' + | identifier variant_type_parameter_list '(' formal_parameter_list? ')' type_parameter_constraints_clause* ';' ; delegate_modifier + : ref_delegate_modifier + | unsafe_modifier // unsafe code support + ; + +ref_delegate_modifier : 'new' | 'public' | 'protected' | 'internal' | 'private' - | unsafe_modifier // unsafe code support ; ``` @@ -30,8 +39,6 @@ delegate_modifier It is a compile-time error for the same modifier to appear multiple times in a delegate declaration. -A delegate declaration shall not supply any *type_parameter_constraints_clause*s unless it also supplies a *variant_type_parameter_list*. - A delegate declaration that supplies a *variant_type_parameter_list* is a generic delegate declaration. Additionally, any delegate nested inside a generic class declaration or a generic struct declaration is itself a generic delegate declaration, since type arguments for the containing type shall be supplied to create a constructed type ([§8.4](types.md#84-constructed-types)). The `new` modifier is only permitted on delegates declared within another type, in which case it specifies that such a delegate hides an inherited member by the same name, as described in [§15.3.5](classes.md#1535-the-new-modifier). @@ -40,11 +47,13 @@ The `public`, `protected`, `internal`, and `private` modifiers control the acces The delegate’s type name is *identifier*. -As with methods ([§15.6.1](classes.md#1561-general)), if `ref` is present, the delegate returns-by-ref; otherwise, if *return_type* is `void`, the delegate returns-no-value; otherwise, the delegate returns-by-value. It is a compile-time error to have both `ref` and a *return_type* of `void`. +As with methods ([§15.6.1](classes.md#1561-general)), if `ref` is present, the delegate returns-by-ref; otherwise, if *return_type* is `void`, the delegate returns-no-value; otherwise, the delegate returns-by-value. The optional *formal_parameter_list* specifies the parameters of the delegate. -*return_type* indicates the return type of the delegate. The optional `ref` indicates that a *variable reference* ([§9.5](variables.md#95-variable-references)) is returned, with the optional `readonly` indicating that that variable is read-only. +The *return_type* of a returns-by-value or returns-no-value delegate declaration specifies the type of the result, if any, returned by the delegate. + +The *ref_return_type* of a returns-by-ref delegate declaration specifies the type of the variable referenced by the *variable_reference* ([§9.5](variables.md#95-variable-references)) returned by the delegate. The optional *variant_type_parameter_list* ([§18.2.3](interfaces.md#1823-variant-type-parameter-lists)) specifies the type parameters to the delegate itself. @@ -76,7 +85,7 @@ The only way to declare a delegate type is via a *delegate_declaration*. Every d ## 20.3 Delegate members -Every delegate type inherits members from the `Delegate` class as described in [§15.3.4](classes.md#1534-inheritance). In addition, every delegate type must provide a non-generic `Invoke` method whose parameter list matches the *formal_parameter_list* in the delegate declaration, and whose return type matches the *return_type* in the delegate declaration. The `Invoke` method shall be at least as accessible as the containing delegate type. Calling the `Invoke` method on a delegate type is semantically equivalent to using the delegate invocation syntax ([§20.6](delegates.md#206-delegate-invocation)) . +Every delegate type inherits members from the `Delegate` class as described in [§15.3.4](classes.md#1534-inheritance). In addition, every delegate type must provide a non-generic `Invoke` method whose parameter list matches the *formal_parameter_list* in the delegate declaration, whose return type matches the *return_type* or *ref_return_type* in the delegate declaration, and for returns-by-ref delegates whose *ref_kind* matches that in the delegate declaration. The `Invoke` method shall be at least as accessible as the containing delegate type. Calling the `Invoke` method on a delegate type is semantically equivalent to using the delegate invocation syntax ([§20.6](delegates.md#206-delegate-invocation)) . Implementations may define additional members in the delegate type. @@ -92,7 +101,7 @@ A method or delegate type `M` is ***compatible*** with a delegate type `D` if al - One of the following is true: - `D` and `M` are both *returns-no-value* - `D` and `M` are returns-by-value ([§15.6.1](classes.md#1561-general), [§20.2](delegates.md#202-delegate-declarations)), and an identity or implicit reference conversion exists from the return type of `M` to the return type of `D`. - - `D` and `M` are both returns-by-ref, and an identity conversion exists between the return type of `M` and the return type of `D`, and both have a *return_type* preceded by `ref readonly`, or both have a *return_type* preceded by `ref` only. + - `D` and `M` are both returns-by-ref, an identity conversion exists between the return type of `M` and the return type of `D`, and both have the same *ref_kind*. This definition of compatibility allows covariance in return type and contravariance in parameter types. diff --git a/standard/expressions.md b/standard/expressions.md index 99aba5434..b9be3ac4b 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -1539,7 +1539,7 @@ simple_name A *simple_name* is either of the form `I` or of the form `I`, where `I` is a single identifier and `I` is an optional *type_argument_list*. When no *type_argument_list* is specified, consider `e` to be zero. The *simple_name* is evaluated and classified as follows: - If `e` is zero and the *simple_name* appears within a local variable declaration space ([§7.3](basic-concepts.md#73-declarations)) that directly contains a local variable, parameter or constant with name `I`, then the *simple_name* refers to that local variable, parameter or constant and is classified as a variable or value. -- If `e` is zero and the *simple_name* appears within a generic method declaration but outside the *attributes* of its *method_header,* and if that declaration includes a type parameter with name `I`, then the *simple_name* refers to that type parameter. +- If `e` is zero and the *simple_name* appears within a generic method declaration but outside the *attributes* of its *method_declaration*, and if that declaration includes a type parameter with name `I`, then the *simple_name* refers to that type parameter. - Otherwise, for each instance type `T` ([§15.3.2](classes.md#1532-the-instance-type)), starting with the instance type of the immediately enclosing type declaration and continuing with the instance type of each enclosing class or struct declaration (if any): - If `e` is zero and the declaration of `T` includes a type parameter with name `I`, then the *simple_name* refers to that type parameter. - Otherwise, if a member lookup ([§12.5](expressions.md#125-member-lookup)) of `I` in `T` with `e` type arguments produces a match: @@ -4749,7 +4749,7 @@ The first operand of the `?:` operator shall be an expression that can be impli If `ref` is present: - An identity conversion must exist between the types of the two *variable_reference*s, and type of the result can be either type. If either type is `dynamic`, type inference prefers `dynamic` ([§8.7](types.md#87-the-dynamic-type)). If either type is a tuple type ([§8.3.11](types.md#8311-tuple-types)), type inference includes the element names when the element names in the same ordinal position match in both tuples. -- The result is a variable reference, which is writeable if both *variable_reference*s are writeable. +- The result is a variable reference, which is writeable if both *variable_reference*s are writeable. > *Note*: When `ref` is present, the *conditional_expression* returns a variable reference, which can be assigned to a reference variable using the `= ref` operator or passed as a reference/input/output parameter. *end note* diff --git a/standard/interfaces.md b/standard/interfaces.md index c797dcab0..9f9aaa8dd 100644 --- a/standard/interfaces.md +++ b/standard/interfaces.md @@ -254,16 +254,21 @@ Interface methods are declared using *interface_method_declaration*s: ```ANTLR interface_method_declaration - : attributes? 'new'? return_type identifier type_parameter_list? - '(' formal_parameter_list? ')' type_parameter_constraints_clause* ';' + : attributes? 'new'? return_type interface_method_header + | attributes? 'new'? ref_kind ref_return_type interface_method_header + ; + +interface_method_header + : identifier '(' formal_parameter_list? ')' ';' + | identifier type_parameter_list '(' formal_parameter_list? ')' type_parameter_constraints_clause* ';' ; ``` -The *attributes*, *return_type*, *identifier*, and *formal_parameter_list* of an interface method declaration have the same meaning as those of a method declaration in a class ([§15.6](classes.md#156-methods)). An interface method declaration is not permitted to specify a method body, and the declaration therefore always ends with a semicolon. An *interface_method_declaration* shall not have *type_parameter_constraints_clause*s unless it also has a *type_parameter_list*. +The *attributes*, *return_type*, *ref_return_type*, *identifier*, and *formal_parameter_list* of an interface method declaration have the same meaning as those of a method declaration in a class ([§15.6](classes.md#156-methods)). An interface method declaration is not permitted to specify a method body, and the declaration therefore always ends with a semicolon. All formal parameter types of an interface method shall be input-safe ([§18.2.3.2](interfaces.md#18232-variance-safety)), and the return type shall be either `void` or output-safe. In addition, any output or reference formal parameter types shall also be output-safe. -> *Note*: Output parameters are required to be input-safe due to common implementation restrictions. *end note* +> *Note*: Output parameters are required to be input-safe due to common implementation restrictions. *end note* Furthermore, each class type constraint, interface type constraint and type parameter constraint on any type parameters of the method shall be input-safe. @@ -313,21 +318,24 @@ Interface properties are declared using *interface_property_declaration*s: ```ANTLR interface_property_declaration : attributes? 'new'? type identifier '{' interface_accessors '}' + | attributes? 'new'? ref_kind type identifier '{' ref_interface_accessor '}' ; -``` -```ANTLR interface_accessors : attributes? 'get' ';' | attributes? 'set' ';' | attributes? 'get' ';' attributes? 'set' ';' | attributes? 'set' ';' attributes? 'get' ';' ; + +ref_interface_accessor + : attributes? 'get' ';' + ; ``` The *attributes*, *type*, and *identifier* of an interface property declaration have the same meaning as those of a property declaration in a class ([§15.7](classes.md#157-properties)). -The accessors of an interface property declaration correspond to the accessors of a class property declaration ([§15.7.3](classes.md#1573-accessors)), except that the accessor body shall always be a semicolon. Thus, the accessors simply indicate whether the property is read-write, read-only, or write-only. +The accessors of an interface property declaration correspond to the accessors of a class property declaration ([§15.7.3](classes.md#1573-accessors)), except that the *accessor_body* shall always be a semicolon. Thus, the accessors simply indicate whether the property is read-write, read-only, or write-only. The type of an interface property shall be output-safe if there is a get accessor, and shall be input-safe if there is a set accessor. @@ -350,15 +358,17 @@ The type of an interface event shall be input-safe. Interface indexers are declared using *interface_indexer_declaration*s: ```ANTLR -interface_indexer_declaration: - attributes? 'new'? type 'this' '[' formal_parameter_list ']' - '{' interface_accessors '}' +interface_indexer_declaration + : attributes? 'new'? type 'this' '[' formal_parameter_list ']' + '{' interface_accessors '}' + | attributes? 'new'? ref_kind type 'this' '[' formal_parameter_list ']' + '{' ref_interface_accessor '}' ; ``` The *attributes*, *type*, and *formal_parameter_list* of an interface indexer declaration have the same meaning as those of an indexer declaration in a class ([§15.9](classes.md#159-indexers)). -The accessors of an interface indexer declaration correspond to the accessors of a class indexer declaration ([§15.9](classes.md#159-indexers)), except that the accessor body shall always be a semicolon. Thus, the accessors simply indicate whether the indexer is read-write, read-only, or write-only. +The accessors of an interface indexer declaration correspond to the accessors of a class indexer declaration ([§15.9](classes.md#159-indexers)), except that the *accessor_body* shall always be a semicolon. Thus, the accessors simply indicate whether the indexer is read-write, read-only, or write-only. All the formal parameter types of an interface indexer shall be input-safe ([§18.2.3.2](interfaces.md#18232-variance-safety)). In addition, any output or reference formal parameter types shall also be output-safe. diff --git a/standard/lexical-structure.md b/standard/lexical-structure.md index c01b8a64a..ba0155e7d 100644 --- a/standard/lexical-structure.md +++ b/standard/lexical-structure.md @@ -1297,7 +1297,7 @@ Conditional compilation directives shall be written in groups consisting of, in At most one of the contained conditional sections is selected for normal lexical processing: -- The *PP_Expression*s of the `#if` and `#elif` directives are evaluated in order until one yields `true`. If an expression yields `true`, the conditional section following the corresponding directive is selected. +- The *PP_Expression*s of the `#if` and `#elif` directives are evaluated in order until one yields `true`. If an expression yields `true`, the conditional section following the corresponding directive is selected. - If all *PP_Expression*s yield `false`, and if a `#else` directive is present, the conditional section following the `#else` directive is selected. - Otherwise, no conditional section is selected. diff --git a/standard/statements.md b/standard/statements.md index bb8f04f34..8650879b4 100644 --- a/standard/statements.md +++ b/standard/statements.md @@ -298,7 +298,7 @@ A *local_variable_declaration* declares one or more local variables. ```ANTLR local_variable_declaration - : ('ref' 'readonly'?)? local_variable_type local_variable_declarators + : ref_kind? local_variable_type local_variable_declarators ; local_variable_type @@ -356,7 +356,7 @@ The value of a local variable is obtained in an expression using a *simple_name* The scope of a local variable declared in a *local_variable_declaration* is the block in which the declaration occurs. It is an error to refer to a local variable in a textual position that precedes the *local_variable_declarator* of the local variable. Within the scope of a local variable, it is a compile-time error to declare another local variable or constant with the same name. -A local variable declaration that declares multiple variables is equivalent to multiple declarations of single variables with the same type and `ref`/`ref readonly` prefix. Furthermore, a variable initializer in a local variable declaration corresponds exactly to an assignment statement that is inserted immediately after the declaration. +A local variable declaration that declares multiple variables is equivalent to multiple declarations of single variables with the same type and *ref_kind*. Furthermore, a variable initializer in a local variable declaration corresponds exactly to an assignment statement that is inserted immediately after the declaration. > *Example*: The example > @@ -446,16 +446,18 @@ A *local_function_declaration* declares a local function. ```ANTLR local_function_declaration - : local_function_header local_function_body + : local_function_modifier* return_type local_function_header local_function_body + | ref_kind ref_return_type local_function_header ref_local_function_body ; local_function_header - : local_function_modifier* ('ref' 'readonly'?)? return_type identifier type_parameter_list? - '(' formal_parameter_list? ')' type_parameter_constraints_clause* + : identifier '(' formal_parameter_list? ')' + | identifier type_parameter_list '(' formal_parameter_list? ')' type_parameter_constraints_clause* ; + local_function_modifier : 'async' - | 'unsafe' + | unsafe_modifier // unsafe code support ; local_function_body @@ -463,6 +465,11 @@ local_function_body | '=>' null_conditional_invocation_expression ';' | '=>' expression ';' ; + +ref_local_function_body + : block + | '=>' 'ref' variable_reference ';' + ; ``` Grammar note: When recognising a *local_function_body* if both the *null_conditional_invocation_expression* and *expression* alternatives are applicable then the former shall be chosen. ([§15.6.1](classes.md#1561-general)) @@ -1037,7 +1044,7 @@ The `foreach` statement enumerates the elements of a collection, executing an em ```ANTLR foreach_statement - : 'foreach' '(' ('ref' 'readonly'?)? local_variable_type identifier 'in' + : 'foreach' '(' ref_kind? local_variable_type identifier 'in' expression ')' embedded_statement ; ``` @@ -1452,7 +1459,7 @@ It is a compile-time error to use a return-by-ref from a method declared with th A function member is said to ***compute a value*** if it is a method with a returns-by-value method ([§15.6.11](classes.md#15611-method-body)), a returns-by-value `get` accessor of a property or indexer, or a user-defined operator. Function members that are returns-no-value do not compute a value and are methods with the effective return type `void`, `set` accessors of properties and indexers, `add` and `remove` accessors of event, instance constructors, static constructors and finalizers. Function members that are returns-by-ref do not compute a value. -For a return-by-value, an implicit conversion ([§10.2](conversions.md#102-implicit-conversions)) shall exist from the type of *expression* to the effective return type ([§15.6.11](classes.md#15611-method-body)) of the containing function member. For a return-by-ref, an identity conversion ([§10.2.2](conversions.md#1022-identity-conversion)) shall exist between the type of *expression* and the effective return type of the containing function member. +For a return-by-value, an implicit conversion ([§10.2](conversions.md#102-implicit-conversions)) shall exist from the type of *expression* to the effective return type ([§15.6.11](classes.md#15611-method-body)) of the containing function member. For a return-by-ref, an identity conversion ([§10.2.2](conversions.md#1022-identity-conversion)) shall exist between the type of *expression* and the effective return type of the containing function member. `return` statements can also be used in the body of anonymous function expressions ([§12.19](expressions.md#1219-anonymous-function-expressions)), and participate in determining which conversions exist for those functions ([§10.7.1](conversions.md#1071-general)).