diff --git a/standard/README.md b/standard/README.md index 3dab17333..da434948c 100644 --- a/standard/README.md +++ b/standard/README.md @@ -617,7 +617,7 @@ - [§15.6.2.3.2](classes.md#156232-input-parameters) Input parameters - [§15.6.2.3.3](classes.md#156233-reference-parameters) Reference parameters - [§15.6.2.3.4](classes.md#156234-output-parameters) Output parameters - - [§15.6.2.4](classes.md#15624-parameter-arrays) Parameter arrays + - [§15.6.2.4](classes.md#15624-parameter-collections) Parameter collections - [§15.6.3](classes.md#1563-static-and-instance-methods) Static and instance methods - [§15.6.4](classes.md#1564-virtual-methods) Virtual methods - [§15.6.5](classes.md#1565-override-methods) Override methods diff --git a/standard/arrays.md b/standard/arrays.md index 6aac0e21b..699b40a85 100644 --- a/standard/arrays.md +++ b/standard/arrays.md @@ -144,7 +144,7 @@ When an array type `S[]` implements `IList`, some of the members of the imple ## 17.3 Array creation -Array instances are created by *array_creation_expression*s ([§12.8.17.5](expressions.md#128175-array-creation-expressions)) or by field or local variable declarations that include an *array_initializer* ([§17.7](arrays.md#177-array-initializers)). Array instances can also be created implicitly as part of evaluating an argument list involving a parameter array ([§15.6.2.4](classes.md#15624-parameter-arrays)). +Array instances are created by *array_creation_expression*s ([§12.8.17.5](expressions.md#128175-array-creation-expressions)) or by field or local variable declarations that include an *array_initializer* ([§17.7](arrays.md#177-array-initializers)). Array instances can also be created implicitly as part of evaluating an argument list involving a parameter collection ([§15.6.2.4](classes.md#15624-parameter-collections)). When an array instance is created, the rank and length of each dimension are established and then remain constant for the entire lifetime of the instance. In other words, it is not possible to change the rank of an existing array instance, nor is it possible to resize its dimensions. diff --git a/standard/basic-concepts.md b/standard/basic-concepts.md index 481b26615..641e2c663 100644 --- a/standard/basic-concepts.md +++ b/standard/basic-concepts.md @@ -248,9 +248,9 @@ There are several different types of declaration spaces, as described in the fol - Within all compilation units of a program, *namespace_member_declaration*s within *namespace_declaration*s that have the same fully qualified namespace name are members of a single combined declaration space. Per [§14.3](namespaces.md#143-namespace-declarations), this includes *file_scoped_namespace_declaration*s. - Each *compilation_unit* and *namespace_body* has an ***alias declaration space***. Each *extern_alias_directive* and *using_alias_directive* of the *compilation_unit* or *namespace_body* contributes a member to the alias declaration space ([§14.6.2](namespaces.md#1462-using-alias-directives)). - Each non-partial class, struct, or interface declaration creates a new declaration space. Each partial class, struct, or interface declaration contributes to a declaration space shared by all matching parts in the same program ([§16.2.4](structs.md#1624-partial-modifier)). Names are introduced into this declaration space through *class_member_declaration*s, *struct_member_declaration*s, *interface_member_declaration*s, or *type_parameter*s. Except for overloaded instance constructor declarations and static constructor declarations, a class, struct, or interface cannot contain a member declaration with the same name as the class, struct, or interface. A class, struct, or interface permits the declaration of overloaded methods and indexers. Furthermore, a class or struct permits the declaration of overloaded instance constructors and operators. For example, a class, struct, or interface may contain multiple method declarations with the same name, provided these method declarations differ in their signature ([§7.6](basic-concepts.md#76-signatures-and-overloading)). Note that base classes do not contribute to the declaration space of a class, and base interfaces do not contribute to the declaration space of an interface. Thus, a derived class or interface is allowed to declare a member with the same name as an inherited member. Such a member is said to ***hide*** the inherited member. -- Each delegate declaration creates a new declaration space. Names are introduced into this declaration space through parameters (*fixed_parameter*s and *parameter_array*s) and *type_parameter*s. +- Each delegate declaration creates a new declaration space. Names are introduced into this declaration space through parameters (*fixed_parameter*s and *parameter_collection*s) and *type_parameter*s. - Each enumeration declaration creates a new declaration space. Names are introduced into this declaration space through *enum_member_declarations*. -- Each method declaration, property declaration, property accessor declaration, indexer declaration, indexer accessor declaration, operator declaration, instance constructor declaration, anonymous function, and local function creates a new declaration space called a ***local variable declaration space***. Names are introduced into this declaration space through parameters (*fixed_parameter*s and *parameter_array*s) and *type_parameter*s. The set and init accessor for a property or an indexer introduce the name `value` as a parameter. The body of the function member, anonymous function, or local function, if any, is considered to be nested within the local variable declaration space. When a local variable declaration space and a nested local variable declaration space contain elements with the same name, within the scope of the nested local name, the outer local name is hidden ([§7.7.1](basic-concepts.md#771-general)) by the nested local name. +- Each method declaration, property declaration, property accessor declaration, indexer declaration, indexer accessor declaration, operator declaration, instance constructor declaration, anonymous function, and local function creates a new declaration space called a ***local variable declaration space***. Names are introduced into this declaration space through parameters (*fixed_parameter*s and *parameter_collection*s) and *type_parameter*s. The set and init accessor for a property or an indexer introduce the name `value` as a parameter. The body of the function member, anonymous function, or local function, if any, is considered to be nested within the local variable declaration space. When a local variable declaration space and a nested local variable declaration space contain elements with the same name, within the scope of the nested local name, the outer local name is hidden ([§7.7.1](basic-concepts.md#771-general)) by the nested local name. > *Note*: Discard parameters of anonymous functions ([§12.22.2](expressions.md#12222-anonymous-function-signatures)) do not introduce names into any declaration space. *end note* - Additional local variable declaration spaces may occur within member declarations, anonymous functions and local functions. Names are introduced into these declaration spaces through *pattern*s, *declaration_expression*s, *declaration_statement*s and *exception_specifier*s. Local variable declaration spaces may be nested, but it is an error for a local variable declaration space and a nested local variable declaration space to contain elements with the same name. Thus, within a nested declaration space it is not possible to declare a local variable, local function or constant with the same name as a parameter, type parameter, local variable, local function or constant in an enclosing declaration space. It is possible for two declaration spaces to contain elements with the same name as long as neither declaration space contains the other. Local declaration spaces are created by the following constructs: - Each *variable_initializer* in a field and property declaration introduces its own local variable declaration space, that is not nested within any other local variable declaration space. diff --git a/standard/classes.md b/standard/classes.md index 25ae0934d..f7a5e90d5 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -2279,8 +2279,8 @@ delimited_parameter_list parameter_list : fixed_parameters - | fixed_parameters ',' parameter_array - | parameter_array + | fixed_parameters ',' parameter_collection + | parameter_collection ; fixed_parameters @@ -2308,12 +2308,12 @@ parameter_mode_modifier | 'in' ; -parameter_array - : attributes? 'params' array_type identifier +parameter_collection + : attributes? 'params' type identifier ; ``` -The parameter list consists of one or more comma-separated parameters of which only the last may be a *parameter_array*. +The parameter list consists of one or more comma-separated parameters of which only the last may be a *parameter_collection*. A *fixed_parameter* consists of an optional set of *attributes* ([§23](attributes.md#23-attributes)); an optional `this` modifier; an optional `scoped` modifier; an optional `in`, `out`, `ref` modifier, or `ref readonly`; a *type*; an *identifier*; and an optional *default_argument*. Each *fixed_parameter* declares a parameter of the given type with the given name. The `this` modifier designates the method as an extension method and is only allowed on the first parameter of a static method in a non-generic, non-nested static class. If the parameter is a `struct` type or a type parameter constrained to a `struct`, the `this` modifier may be combined with the `ref`, `ref readonly`, or `in` modifier, but not the `out` modifier. Extension methods are further described in [§15.6.10](classes.md#15610-extension-methods). A *fixed_parameter* with a *default_argument* is known as an ***optional parameter***, whereas a *fixed_parameter* without a *default_argument* is a ***required parameter***. A required parameter shall not appear after an optional parameter in a *parameter_list*. @@ -2331,9 +2331,32 @@ The *expression* shall be implicitly convertible by an identity or nullable conv If optional parameters occur in an implementing partial method declaration ([§15.6.9](classes.md#1569-partial-methods)), an explicit interface member implementation ([§19.6.2](interfaces.md#1962-explicit-interface-member-implementations)), a single-parameter indexer declaration ([§15.9](classes.md#159-indexers)), or in an operator declaration ([§15.10.1](classes.md#15101-general)) a compiler should give a warning, since these members can never be invoked in a way that permits arguments to be omitted. -A *parameter_array* consists of an optional set of *attributes* ([§23](attributes.md#23-attributes)), a `params` modifier, an *array_type*, and an *identifier*. A parameter array declares a single parameter of the given array type with the given name. The *array_type* of a parameter array shall be a single-dimensional array type ([§17.2](arrays.md#172-array-types)). In a method invocation, a parameter array permits either a single argument of the given array type to be specified, or it permits zero or more arguments of the array element type to be specified. Parameter arrays are described further in [§15.6.2.4](classes.md#15624-parameter-arrays). - -A *parameter_array* may occur after an optional parameter, but cannot have a default value – the omission of arguments for a *parameter_array* would instead result in the creation of an empty array. +A *parameter_collection* consists of an optional set of *attributes* ([§23](attributes.md#23-attributes)), a `params` modifier, a *type*, and an *identifier*. A parameter collection declares a single parameter of the given array type with the given name. The *type* of a parameter collection shall be one of the following valid target types for a collection expression: + +- A single dimensional array type `T[]`, in which case the element type is `T` +- A span type + - `System.Span` + - `System.ReadOnlySpan` + in which cases the element type is `T` +- A type with an appropriate collection-creation method ((§15.17.1](classes.md#15171-general)) that can be invoked with no additional arguments, which is at least as accessible as the declaring member, and with a corresponding element type resulting from that determination +- A struct or class type that implements `System.Collections.IEnumerable` where: + - The type has a constructor that can be invoked with no arguments, and the constructor is at least as accessible as the declaring member. + - The type has an instance (not an extension) method `Add` where: + - The method can be invoked with a single value argument. + - If the method is generic, the type arguments can be inferred from the argument. + - The method is at least as accessible as the declaring member. + In which case the element type is the iteration type ([§13.9.5.1]( statements.md#13951-general)) of *type*. +- An interface type + - `System.Collections.Generic.IEnumerable` + - `System.Collections.Generic.IReadOnlyCollection` + - `System.Collections.Generic.IReadOnlyList` + - `System.Collections.Generic.ICollection` + - `System.Collections.Generic.IList` + in which case the element type is `T`. + +In a method invocation, a parameter collection permits either a single argument of the given array type to be specified, or it permits zero or more arguments of the array element type to be specified. Parameter collections are described further in [§15.6.2.4](classes.md#15624-parameter-arrays). + +A *parameter_collection* may occur after an optional parameter, but cannot have a default value – the omission of arguments for a *parameter_collection* would instead result in the creation of an empty collection. > *Example*: The following illustrates different kinds of parameters: > @@ -2351,7 +2374,7 @@ A *parameter_array* may occur after an optional parameter, but cannot have a def > ) { } > ``` > -> In the *parameter_list* for `M`, `i` is a required `ref` parameter, `d` is a required value parameter, `b`, `s`, `o` and `t` are optional value parameters and `a` is a parameter array. +> In the *parameter_list* for `M`, `i` is a required `ref` parameter, `d` is a required value parameter, `b`, `s`, `o` and `t` are optional value parameters and `a` is a parameter collection. > > *end example* @@ -2366,7 +2389,7 @@ The following kinds of parameters exist: - Output parameters ([§15.6.2.3.4](classes.md#156234-output-parameters)). - Reference parameters ([§15.6.2.3.3](classes.md#156233-reference-parameters)). - Reference readonly parameters, which are reference parameters that also have the `readonly` modifier. -- Parameter arrays ([§15.6.2.4](classes.md#15624-parameter-arrays)). +- Parameter collections ([§15.6.2.4](classes.md#15624-parameter-collections)). > *Note*: As described in [§7.6](basic-concepts.md#76-signatures-and-overloading), the `in`, `out`, `ref`, and `ref readonly` modifiers are part of a method’s signature, but the `params` and `scoped` modifiers are not. *end note* @@ -2538,26 +2561,26 @@ A method declared as an optional partial method ([§15.6.9.2](classes.md#15692-o > > *end example* -#### 15.6.2.4 Parameter arrays +#### 15.6.2.4 Parameter collections -A parameter declared with a `params` modifier is a parameter array. If a parameter list includes a parameter array, it shall be the last parameter in the list and it shall be of a single-dimensional array type. +A parameter declared with a `params` modifier is a parameter collection. -> *Example*: The types `string[]` and `string[][]` can be used as the type of a parameter array, but the type `string[,]` cannot. *end example* +> *Example*: The types `string[]` and `string[][]` can be used as the type of a parameter collection, but the type `string[,]` cannot. *end example* > *Note*: It is not possible to combine the `params` modifier with the modifiers `in`, `out`, or `ref`. *end note* -A parameter array permits arguments to be specified in one of two ways in a method invocation: +A parameter collection permits arguments to be specified in one of two ways in a method invocation: -- The argument given for a parameter array can be a single expression that is implicitly convertible ([§10.2](conversions.md#102-implicit-conversions)) to the parameter array type. In this case, the parameter array acts precisely like a value parameter. -- Alternatively, the invocation can specify zero or more arguments for the parameter array, where each argument is an expression that is implicitly convertible ([§10.2](conversions.md#102-implicit-conversions)) to the element type of the parameter array. In this case, the invocation creates an instance of the parameter array type with a length corresponding to the number of arguments, initializes the elements of the array instance with the given argument values, and uses the newly created array instance as the actual argument. +- The argument given for a parameter collection can be a single expression that is implicitly convertible ([§10.2](conversions.md#102-implicit-conversions)) to the parameter collection type. In this case, the parameter collection acts precisely like a value parameter. +- Alternatively, the invocation can specify zero or more arguments for the parameter collection, where each argument is an expression that is implicitly convertible ([§10.2](conversions.md#102-implicit-conversions)) to the element type of the parameter collection. In this case, the invocation creates an instance of the parameter collection type according to the rules specified in [§12.8.25](expressions.md#12825-collection-expressions) as though the arguments were used as expression elements in a collection expression in the same order, and uses the newly created collection instance as the actual argument. When constructing the collection instance, the original unconverted arguments are used. -Except for allowing a variable number of arguments in an invocation, a parameter array is precisely equivalent to a value parameter ([§15.6.2.2](classes.md#15622-value-parameters)) of the same type. +Except for allowing a variable number of arguments in an invocation, a parameter collection is precisely equivalent to a value parameter ([§15.6.2.2](classes.md#15622-value-parameters)) of the same type. > *Example*: The example > -> +> > ```csharp > class Test > { @@ -2602,11 +2625,13 @@ Except for allowing a variable number of arguments in an invocation, a parameter > > The fourth and fifth invocations pass a three-element and an empty collection expression, respectively. *end example* -When performing overload resolution, a method with a parameter array might be applicable, either in its normal form or in its expanded form ([§12.6.4.2](expressions.md#12642-applicable-function-member)). The expanded form of a method is available only if the normal form of the method is not applicable and only if an applicable method with the same signature as the expanded form is not already declared in the same type. +When performing overload resolution, a method with a parameter collection might be applicable, either in its normal form or in its expanded form ([§12.6.4.2](expressions.md#12642-applicable-function-member)). The expanded form of a method is available only if the normal form of the method is not applicable and only if an applicable method with the same signature as the expanded form is not already declared in the same type. + +A potential ambiguity arises between the normal form and the expanded form of the method with a single parameter collection argument when it can be used as the parameter collection itself and as the element of the parameter collection at the same time. The ambiguity presents no problem, however, since it can be resolved by inserting a cast or using a collection expression, if needed. > *Example*: The example > -> +> > ```csharp > class Test > { @@ -2640,17 +2665,17 @@ When performing overload resolution, a method with a parameter array might be ap > F(object[]) > ``` > -> In the example, two of the possible expanded forms of the method with a parameter array are already included in the class as regular methods. These expanded forms are therefore not considered when performing overload resolution, and the first and third method invocations thus select the regular methods. When a class declares a method with a parameter array, it is not uncommon to also include some of the expanded forms as regular methods. By doing so, it is possible to avoid the allocation of an array instance that occurs when an expanded form of a method with a parameter array is invoked. +> In the example, two of the possible expanded forms of the method with a parameter collection are already included in the class as regular methods. These expanded forms are therefore not considered when performing overload resolution, and the first and third method invocations thus select the regular methods. When a class declares a method with a parameter collection, it is not uncommon to also include some of the expanded forms as regular methods. By doing so, it is possible to avoid the allocation of a collection instance that occurs when an expanded form of a method with a parameter collection is invoked. > > *end example* -> An array is a reference type, so the value passed for a parameter array can be `null`. +> An array is a reference type, so the value passed for a parameter collection can be `null`. > > *Example*: The example: > -> +> > ```csharp > class Test > { @@ -2676,11 +2701,11 @@ When performing overload resolution, a method with a parameter array might be ap > > *end example* -When the type of a parameter array is `object[]`, a potential ambiguity arises between the normal form of the method and the expanded form for a single `object` parameter. The reason for the ambiguity is that an `object[]` is itself implicitly convertible to type `object`. The ambiguity presents no problem, however, since it can be resolved by inserting a cast if needed. +When the type of a parameter collection is `object[]`, a potential ambiguity arises between the normal form of the method and the expanded form for a single `object` parameter. The reason for the ambiguity is that an `object[]` is itself implicitly convertible to type `object`. The ambiguity presents no problem, however, since it can be resolved by inserting a cast if needed. > *Example*: The example > -> +> > ```csharp > class Test > { @@ -7024,6 +7049,7 @@ If the target type is an array, a `Span` or `ReadOnlySpan`, a type with a collec > ``` > > *end note* + ## 15.18 Record class and non-record class differences A record class differs from a non-record class in several important ways: diff --git a/standard/delegates.md b/standard/delegates.md index d45b852e5..7f587e21d 100644 --- a/standard/delegates.md +++ b/standard/delegates.md @@ -155,7 +155,7 @@ This definition of compatibility allows covariance in return type and contravari -> *Note*: The intuitive meaning of delegate compatibility is that a method is compatible with a delegate type if every invocation of the delegate could be replaced with an invocation of the method without violating type safety, treating optional parameters and parameter arrays as explicit parameters. For example, in the following code: +> *Note*: The intuitive meaning of delegate compatibility is that a method is compatible with a delegate type if every invocation of the delegate could be replaced with an invocation of the method without violating type safety, treating optional parameters and parameter collections as explicit parameters. For example, in the following code: > > > ```csharp diff --git a/standard/expressions.md b/standard/expressions.md index 404efedd5..bb3687d10 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -553,7 +553,7 @@ Every function member and delegate invocation includes an argument list, which p - For events, the argument list consists of the expression specified as the right operand of the `+=` or `-=` operator. - For user-defined operators, the argument list consists of the single operand of the unary operator or the two operands of the binary operator. -The arguments of properties ([§15.7](classes.md#157-properties)) and events ([§15.8](classes.md#158-events)) are always passed as value parameters ([§15.6.2.2](classes.md#15622-value-parameters)). The arguments of user-defined operators ([§15.10](classes.md#1510-operators)) are always passed as value parameters ([§15.6.2.2](classes.md#15622-value-parameters)) or input parameters ([§9.2.8](variables.md#928-input-parameters)). The arguments of indexers ([§15.9](classes.md#159-indexers)) are always passed as value parameters ([§15.6.2.2](classes.md#15622-value-parameters)), input parameters ([§9.2.8](variables.md#928-input-parameters)), reference parameters of kind `ref readonly` ([§15.6.2.3.3](classes.md#156233-reference-parameters)), or parameter arrays ([§15.6.2.4](classes.md#15624-parameter-arrays)). Output and reference parameters of kind `ref` are not supported for these categories of function members. +The arguments of properties ([§15.7](classes.md#157-properties)) and events ([§15.8](classes.md#158-events)) are always passed as value parameters ([§15.6.2.2](classes.md#15622-value-parameters)). The arguments of user-defined operators ([§15.10](classes.md#1510-operators)) are always passed as value parameters ([§15.6.2.2](classes.md#15622-value-parameters)) or input parameters ([§9.2.8](variables.md#928-input-parameters)). The arguments of indexers ([§15.9](classes.md#159-indexers)) are always passed as value parameters ([§15.6.2.2](classes.md#15622-value-parameters)), input parameters ([§9.2.8](variables.md#928-input-parameters)), reference parameters of kind `ref readonly` ([§15.6.2.3.3](classes.md#156233-reference-parameters)), or parameter collections ([§15.6.2.4](classes.md#15624-parameter-collections)). Output and reference parameters of kind `ref` are not supported for these categories of function members. The arguments of an instance constructor, method, indexer, or delegate invocation are specified as an *argument_list*: @@ -607,14 +607,14 @@ The position of an argument or parameter is defined as the number of arguments o The corresponding parameters for function member arguments are established as follows: - Arguments in the *argument_list* of instance constructors, methods, indexers and delegates: - - A positional argument where a parameter occurs at the same position in the parameter list corresponds to that parameter, unless the parameter is a parameter array and the function member is invoked in its expanded form. - - A positional argument of a function member with a parameter array invoked in its expanded form, which occurs at or after the position of the parameter array in the parameter list, corresponds to an element in the parameter array. + - A positional argument where a parameter occurs at the same position in the parameter list corresponds to that parameter, unless the parameter is a parameter collection and the function member is invoked in its expanded form. + - A positional argument of a function member with a parameter collection invoked in its expanded form, which occurs at or after the position of the parameter collection in the parameter list, corresponds to an element in the parameter collection. - A named argument corresponds to the parameter of the same name in the parameter list. - For indexers, when invoking the set or init accessor, the expression specified as the right operand of the assignment operator corresponds to the implicit `value` parameter of the set or init accessor declaration. - For properties, when invoking the get accessor there are no arguments. When invoking the set or init accessor, the expression specified as the right operand of the assignment operator corresponds to the implicit value parameter of the set or init accessor declaration. - For user-defined unary operators (including conversions), the single operand corresponds to the single parameter of the operator declaration. - For user-defined binary operators, the left operand corresponds to the first parameter, and the right operand corresponds to the second parameter of the operator declaration. -- An unnamed argument corresponds to no parameter when it is after an out-of-position named argument or a named argument that corresponds to a parameter array. +- An unnamed argument corresponds to no parameter when it is after an out-of-position named argument or a named argument that corresponds to a parameter collection. > *Note*: This prevents `void M(bool a = true, bool b = true, bool c = true);` being invoked by `M(c: false, valueB);`. The first argument is used out-of-position (the argument is used in first position, but the parameter named `c` is in third position), so the following arguments should be named. In other words, non-trailing named arguments are only allowed when the name and the position result in finding the same corresponding parameter. *end note* #### 12.6.2.3 Run-time evaluation of argument lists @@ -667,10 +667,10 @@ During the run-time processing of a function member invocation ([§12.6.6](expre > > *end example* -Methods, indexers, and instance constructors may declare their right-most parameter to be a parameter array ([§15.6.2.4](classes.md#15624-parameter-arrays)). Such function members are invoked either in their normal form or in their expanded form depending on which is applicable ([§12.6.4.2](expressions.md#12642-applicable-function-member)): +Methods, indexers, and instance constructors may declare their right-most parameter to be a parameter collection ([§15.6.2.4](classes.md#15624-parameter-collections)). Such function members are invoked either in their normal form or in their expanded form depending on which is applicable ([§12.6.4.2](expressions.md#12642-applicable-function-member)): -- When a function member with a parameter array is invoked in its normal form, the argument given for the parameter array shall be a single expression that is implicitly convertible ([§10.2](conversions.md#102-implicit-conversions)) to the parameter array type. In this case, the parameter array acts precisely like a value parameter. -- When a function member with a parameter array is invoked in its expanded form, the invocation shall specify zero or more positional arguments for the parameter array, where each argument is an expression that is implicitly convertible ([§10.2](conversions.md#102-implicit-conversions)) to the element type of the parameter array. In this case, the invocation creates an instance of the parameter array type with a length corresponding to the number of arguments, initializes the elements of the array instance with the given argument values, and uses the newly created array instance as the actual argument. +- When a function member with a parameter collection is invoked in its normal form, the argument given for the parameter collection shall be a single expression that is implicitly convertible ([§10.2](conversions.md#102-implicit-conversions)) to the parameter collection type. In this case, the parameter collection acts precisely like a value parameter. +- When a function member with a parameter collection is invoked in its expanded form, the invocation shall specify zero or more positional arguments for the parameter collection, where each argument is an expression that is implicitly convertible ([§10.2](conversions.md#102-implicit-conversions)) to the element type of the parameter collection. In this case, the invocation creates an instance of the parameter collection type with a length corresponding to the number of arguments, initializes the elements of the array instance with the given argument values, and uses the newly created array instance as the actual argument. The expressions of an argument list are always evaluated in textual order. @@ -701,7 +701,7 @@ The expressions of an argument list are always evaluated in textual order. > > *end example* -When a function member with a parameter array is invoked in its expanded form with at least one expanded argument, the invocation is processed as if an array creation expression with an array initializer ([§12.8.17.5](expressions.md#128175-array-creation-expressions)) was inserted around the expanded arguments. An empty array is passed when there are no arguments for the parameter array; it is unspecified whether the reference passed is to a newly allocated or existing empty array. +When a function member with a parameter collection is invoked in its expanded form with at least one expanded argument, the invocation is processed as if the expanded arguments were the *collection_element*s of a *collection_expression* ([§12.8.25](expressions.md#12825-collection-expressions)). An empty collection is passed when there are no arguments for the parameter collection; it is unspecified whether the reference passed is to a newly allocated or existing empty collection. > *Example*: Given the declaration > @@ -1077,20 +1077,20 @@ A function member is said to be an ***applicable function member*** with respect - Each argument in `A` corresponds to a parameter in the function member declaration as described in [§12.6.2.2](expressions.md#12622-corresponding-parameters), at most one argument corresponds to each parameter, and any parameter to which no argument corresponds is an optional parameter. - For each argument in `A`, the parameter-passing mode of the argument is identical to the parameter-passing mode of the corresponding parameter, and - - for a value parameter or a parameter array, an implicit conversion ([§10.2](conversions.md#102-implicit-conversions)) exists from the argument expression to the type of the corresponding parameter, or + - for a value parameter or a parameter collection, an implicit conversion ([§10.2](conversions.md#102-implicit-conversions)) exists from the argument expression to the type of the corresponding parameter, or - for a reference parameter whose type is a struct type, an implicit interpolated string handler conversion exists from the argument to the type of the corresponding parameter, or - for a reference or output parameter, there is an identity conversion between the type of the argument expression (if any) and the type of the corresponding parameter, or - for an input parameter when the corresponding argument has the `in` modifier, there is an identity conversion between the type of the argument expression (if any) and the type of the corresponding parameter, or - for an input parameter when the corresponding argument omits the `in` modifier, an implicit conversion ([§10.2](conversions.md#102-implicit-conversions)) exists from the argument expression to the type of the corresponding parameter. - for a `ref readonly` parameter when the corresponding argument omits the `ref` modifier, an implicit conversion ([§10.2](conversions.md#102-implicit-conversions)) exists from the argument expression to the type of the corresponding parameter. -For a function member that includes a parameter array, if the function member is applicable by the above rules, it is said to be applicable in its ***normal form***. If a function member that includes a parameter array is not applicable in its normal form, the function member might instead be applicable in its ***expanded form***: +For a function member that includes a parameter collection, if the function member is applicable by the above rules, it is said to be applicable in its ***normal form***. If a function member that includes a parameter collection is not applicable in its normal form, the function member might instead be applicable in its ***expanded form***: -- The expanded form is constructed by replacing the parameter array in the function member declaration with zero or more value parameters of the element type of the parameter array such that the number of arguments in the argument list `A` matches the total number of parameters. If `A` has fewer arguments than the number of fixed parameters in the function member declaration, the expanded form of the function member cannot be constructed and is thus not applicable. +- The expanded form is constructed by replacing the parameter collection in the function member declaration with zero or more value parameters of the collection's element type such that the number of arguments in the argument list `A` matches the total number of parameters. If `A` has fewer arguments than the number of fixed parameters in the function member declaration, the expanded form of the function member cannot be constructed and is thus not applicable. - Otherwise, the expanded form is applicable if for each argument in `A`, one of the following is true: - the parameter-passing mode of the argument is identical to the parameter-passing mode of the corresponding parameter, and: - for a fixed value parameter or a value parameter created by the expansion, an implicit conversion ([§10.2](conversions.md#102-implicit-conversions)) exists from the argument expression to the type of the corresponding parameter; or - - for a by-reference parameter, the type of the argument expression is identical to the type of the corresponding parameter. + - for an `in`, `out`, or `ref` parameter, the type of the argument expression is identical to the type of the corresponding parameter. - the parameter-passing mode of the argument is value, and the parameter-passing mode of the corresponding parameter is input or `ref readonly`, and an implicit conversion ([§10.2](conversions.md#102-implicit-conversions)) exists from the argument expression to the type of the corresponding parameter. When the implicit conversion from the argument type to the parameter type of an input parameter is a dynamic implicit conversion ([§10.2.10](conversions.md#10210-implicit-dynamic-conversions)), the results are undefined. @@ -1099,9 +1099,9 @@ When the implicit conversion from the argument type to the parameter type of an > > > ```csharp -> public static void M1(int p1) { ... } -> public static void M1(in int p1) { ... } -> public static void M2(in int p1) { ... } +> public static void M1(int p1) { … } +> public static void M1(in int p1) { … } +> public static void M2(in int p1) { … } > public static void Test() > { > int i = 10; uint ui = 34U; @@ -1138,27 +1138,32 @@ Parameter lists for each of the candidate function members are constructed in th - Reference and output parameters are removed from the parameter list - The parameters are reordered so that they occur at the same position as the corresponding argument in the argument list. -Given an argument list `A` with a set of argument expressions `{E₁, E₂, ..., Eᵥ}` and two applicable function members `Mᵥ` and `Mₓ` with parameter types `{P₁, P₂, ..., Pᵥ}` and `{Q₁, Q₂, ..., Qᵥ}`, `Mᵥ` is defined to be a ***better function member*** than `Mₓ` if +Given an argument list `A` with a set of argument expressions `{E₁, E₂, …, Eᵥ}` and two applicable function members `Mᵥ` and `Mₓ` with parameter types `{P₁, P₂, …, Pᵥ}` and `{Q₁, Q₂, …, Qᵥ}`, `Mᵥ` is defined to be a ***better function member*** than `Mₓ` if - for each argument, the implicit conversion from `Eᵥ` to `Pᵥ` is not an anonymous function type conversion, and - - `Mᵥ` is a non-generic method or `Mᵥ` is a generic method with type parameters `{X₁, X₂, ..., Xᵥ}` and for each type parameter the type argument is inferred from an expression or from a type other than an anonymous function type, and - - for at least one argument, the implicit conversion from `Eᵥ` to `Qᵥ` is an anonymous function type conversion, or `Mₓ` is a generic method with type parameters `{Y₁, Y₂, ..., Yᵥ}` and for at least one type parameter the type argument is inferred from an anonymous function type, or + - `Mᵥ` is a non-generic method or `Mᵥ` is a generic method with type parameters `{X₁, X₂, …, Xᵥ}` and for each type parameter the type argument is inferred from an expression or from a type other than an anonymous function type, and + - for at least one argument, the implicit conversion from `Eᵥ` to `Qᵥ` is an anonymous function type conversion, or `Mₓ` is a generic method with type parameters `{Y₁, Y₂, …, Yᵥ}` and for at least one type parameter the type argument is inferred from an anonymous function type, or -- for each argument, the implicit conversion from `Eᵥ` to `Qᵥ` is not better than the implicit conversion from `Eᵥ` to `Pᵥ`, and for at least one argument, the conversion from `Eᵥ` to `Pᵥ` is better than the conversion from `Eᵥ` to `Qᵥ`. +- for each argument, the implicit conversion from `Eᵥ` to `Qᵥ` is not better than the implicit conversion from `Eᵥ` to `Pᵥ`, and +- for at least one argument, the conversion from `Eᵥ` to `Pᵥ` is better than the conversion from `Eᵥ` to `Qᵥ`. -In case the parameter type sequences `{P₁, P₂, ..., Pᵥ}` and `{Q₁, Q₂, ..., Qᵥ}` are equivalent (i.e., each `Pᵢ` has an identity conversion to the corresponding `Qᵢ`), the following tie-breaking rules are applied, in order, to determine the better function member. +In case the parameter type sequences `{P₁, P₂, …, Pᵥ}` and `{Q₁, Q₂, …, Qᵥ}` are equivalent (i.e., each `Pᵢ` has an identity conversion to the corresponding `Qᵢ`), the following tie-breaking rules are applied, in order, to determine the better function member. - If `Mᵢ` is a non-generic method and `Mₑ` is a generic method, then `Mᵢ` is better than `Mₑ`. -- Otherwise, if `Mᵢ` is applicable in its normal form and `Mₑ` has a params array and is applicable only in its expanded form, then `Mᵢ` is better than `Mₑ`. -- Otherwise, if both methods have params arrays and are applicable only in their expanded forms, and if the params array of `Mᵢ` has fewer elements than the params array of `Mₑ`, then `Mᵢ` is better than `Mₑ`. -- Otherwise, if `Mᵥ` has more specific parameter types than `Mₓ`, then `Mᵥ` is better than `Mₓ`. Let `{R1, R2, ..., Rn}` and `{S1, S2, ..., Sn}` represent the uninstantiated and unexpanded parameter types of `Mᵥ` and `Mₓ`. `Mᵥ`’s parameter types are more specific than `Mₓ`s if, for each parameter, `Rx` is not less specific than `Sx`, and, for at least one parameter, `Rx` is more specific than `Sx`: +- Otherwise, if `Mᵢ` is applicable in its normal form and `Mₑ` has a parameter collection and is applicable only in its expanded form, then `Mᵢ` is better than `Mₑ`. +- Otherwise, if both methods have parameter collections and are applicable only in their expanded forms, and if the parameter collection of `Mᵢ` has fewer elements than the parameter collection of `Mₑ`, then `Mᵢ` is better than `Mₑ`. +- Otherwise, if `Mᵥ` has more specific parameter types than `Mₓ`, then `Mᵥ` is better than `Mₓ`. Let `{R1, R2, …, Rn}` and `{S1, S2, …, Sn}` represent the uninstantiated and unexpanded parameter types of `Mᵥ` and `Mₓ`. `Mᵥ`’s parameter types are more specific than `Mₓ`s if, for each parameter, `Rx` is not less specific than `Sx`, and, for at least one parameter, `Rx` is more specific than `Sx`: - A type parameter is less specific than a non-type parameter. - Recursively, a constructed type is more specific than another constructed type (with the same number of type arguments) if at least one type argument is more specific and no type argument is less specific than the corresponding type argument in the other. - An array type is more specific than another array type (with the same number of dimensions) if the element type of the first is more specific than the element type of the second. - Otherwise if one member is a non-lifted operator and the other is a lifted operator, the non-lifted one is better. - If neither function member was found to be better, and all parameters of `Mᵥ` have a corresponding argument whereas default arguments need to be substituted for at least one optional parameter in `Mₓ`, then `Mᵥ` is better than `Mₓ`. - If for at least one parameter `Mᵥ` uses the ***better parameter-passing choice*** ([§12.6.4.4](expressions.md#12644-better-parameter-passing-mode)) than the corresponding parameter in `Mₓ` and none of the parameters in `Mₓ` use the better parameter-passing choice than `Mᵥ`, `Mᵥ` is better than `Mₓ`. +- Otherwise, if both methods have parameter collections and are applicable only in their expanded forms then `Mᵢ` is better than `Mₑ` if the same set of arguments corresponds to the collection elements for both methods, and one of the following holds: + - both parameter collections are not *span_type*s, and an implicit conversion exists from the parameter collection of `Mᵢ` to the parameter collection of `Mₑ` + - the parameter collection of `Mᵢ` is `System.ReadOnlySpan`, and the parameter collection of `Mₑ` is `System.Span`, and an identity conversion exists from `Eᵢ` to `Eₑ` + - the parameter collection of `Mᵢ` is `System.ReadOnlySpan` or `System.Span`, and the parameter collection of `Mₑ` is an array or array interface type with element type `Eₑ`, and an identity conversion exists from `Eᵢ` to `Eₑ` - Otherwise, no function member is better. A `delegate*` is more specific than `void*`. @@ -1171,8 +1176,8 @@ It is permitted to have corresponding parameters in two overloaded methods diffe ```csharp -public static void M1(int p1) { ... } -public static void M1(in int p1) { ... } +public static void M1(int p1) { … } +public static void M1(in int p1) { … } ``` Given `int i = 10;`, according to [§12.6.4.2](expressions.md#12642-applicable-function-member), the calls `M1(i)` and `M1(i + 5)` result in both overloads being applicable. In such cases, the method with the parameter-passing mode of value is the ***better parameter-passing mode choice***. @@ -1261,8 +1266,8 @@ Given two types `T₁` and `T₂`, `T₁` is a ***better conversion target*** th > > > ```csharp -> public interface I1 { ... } -> public interface I2 { ... } +> public interface I1 { … } +> public interface I2 { … } > > public abstract class G1 > { @@ -1376,12 +1381,12 @@ An expression `E`, with a type `S` other than `dynamic`, can be ***deconstructed - If `E` is a *tuple-literal* the result of deconstruction is the expression `E` itself. -- Otherwise, if `E` has a tuple type `(T₁, ..., Tₙ)`, then the result of deconstruction is semantically equivalent to the expression `(E.Item1, ..., E.Itemn)` except `E` is evaluated only once. +- Otherwise, if `E` has a tuple type `(T₁, …, Tₙ)`, then the result of deconstruction is semantically equivalent to the expression `(E.Item1, …, E.Itemn)` except `E` is evaluated only once. - Otherwise if there is a unique instance or extension method `S.Deconstruct`; with `n ≥ 2` output parameters, with types `T₁` to `Tₙ`, and no other parameters; then `E` can be deconstructed. The result of the deconstruction is semantically equivalent to replacing `E` with the following pseudo-code: >```csharp - > E.Deconstruct(out T1 v1, ..., out TN vn) andThen (v1, ..., vn); + > E.Deconstruct(out T1 v1, …, out TN vn) andThen (v1, …, vn); >``` Where `andThen` is a pseudo C# operation which performs its left-hand operand and then returns its right-operand as the result. @@ -5920,7 +5925,7 @@ A non-`static` local function or non-`static` anonymous function can capture sta A *lambda_expression* shall not contain any *parameter_modifier*s with the `this` modifier. -An *anonymous_method_expression* shall not contain any *default_argument*s or *parameter_array*s. +An *anonymous_method_expression* shall not contain any *default_argument*s or *parameter_collection*s. When recognising an *anonymous_function_body* if both the *null_conditional_invocation_expression* and *expression* alternatives are applicable then the former shall be chosen. @@ -6002,7 +6007,7 @@ The behavior of *lambda_expression*s and *anonymous_method_expression*s is the s - Only *lambda_expression*s have conversions to compatible expression tree types ([§8.6](types.md#86-expression-tree-types)). - Only *lambda_expression* parameters may contain ‘scoped’. - Only *lambda_expression*s may have *attributes* and explicit return types. -- An *anonymous_method_expression* may not contain any *default_argument*s or *parameter_array*s. +- An *anonymous_method_expression* may not contain any *default_argument*s or *parameter_collection*s. The contextual keyword `var` shall not be used as an explicit return type in a *lambda_expression*. @@ -6112,7 +6117,7 @@ An anonymous function cannot be a receiver, argument, or operand of a dynamicall #### 12.22.6.1 General -Any local variable, value parameter, or parameter array whose scope includes the *lambda_expression* or *anonymous_method_expression* is called an ***outer variable*** of the anonymous function. In an instance function member of a class, the `this` value is considered a value parameter and is an outer variable of any anonymous function contained within the function member. +Any local variable, value parameter, or parameter collection whose scope includes the *lambda_expression* or *anonymous_method_expression* is called an ***outer variable*** of the anonymous function. In an instance function member of a class, the `this` value is considered a value parameter and is an outer variable of any anonymous function contained within the function member. If the modifier `static` is present, the anonymous function cannot capture state from the enclosing scope. As a result, locals, parameters, and `this` from the enclosing scope are not available to that anonymous function. diff --git a/standard/interfaces.md b/standard/interfaces.md index 10d5a9169..bccf73eb1 100644 --- a/standard/interfaces.md +++ b/standard/interfaces.md @@ -907,7 +907,7 @@ A *type_parameter_constraints_clause* on an explicit interface method implementa > > *end note* -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 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 collection, 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 collection then an associated explicit interface member implementation shall not have a parameter collection. 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. diff --git a/standard/unsafe-code.md b/standard/unsafe-code.md index ec1327b38..42f1c5759 100644 --- a/standard/unsafe-code.md +++ b/standard/unsafe-code.md @@ -410,7 +410,7 @@ The `&` operator ([§24.6.5](unsafe-code.md#2465-the-address-of-operator)) permi In precise terms, a fixed variable is one of the following: -- A variable resulting from a *simple_name* ([§12.8.4](expressions.md#1284-simple-names)) that refers to a local variable, value parameter, or parameter array, unless the variable is captured by a non-`static` anonymous function ([§12.22.6.2](expressions.md#122262-captured-outer-variables)). +- A variable resulting from a *simple_name* ([§12.8.4](expressions.md#1284-simple-names)) that refers to a local variable, value parameter, or parameter collection, unless the variable is captured by a non-`static` anonymous function ([§12.22.6.2](expressions.md#122262-captured-outer-variables)). - A variable resulting from a *member_access* ([§12.8.7](expressions.md#1287-member-access)) of the form `V.I`, where `V` is a fixed variable of a *struct_type*. - A variable resulting from a *pointer_indirection_expression* ([§24.6.2](unsafe-code.md#2462-pointer-indirection)) of the form `*P`, a *pointer_member_access* ([§24.6.3](unsafe-code.md#2463-pointer-member-access)) of the form `P->I`, or a *pointer_element_access* ([§24.6.4](unsafe-code.md#2464-pointer-element-access)) of the form `P[E]`. @@ -743,7 +743,7 @@ The `&` operator does not require its operand to be definitely assigned, but fol -> *Note*: When a local variable, value parameter, or parameter array is captured by an anonymous function ([§12.8.24](expressions.md#12824-anonymous-method-expressions)), that local variable, parameter, or parameter array is no longer considered to be a fixed variable ([§24.7](unsafe-code.md#247-the-fixed-statement)), but is instead considered to be a moveable variable. Thus it is an error for any unsafe code to take the address of a local variable, value parameter, or parameter array that has been captured by an anonymous function. *end note* +> *Note*: When a local variable, value parameter, or parameter collection is captured by an anonymous function ([§12.8.24](expressions.md#12824-anonymous-method-expressions)), that local variable, parameter, or parameter collection is no longer considered to be a fixed variable ([§24.7](unsafe-code.md#247-the-fixed-statement)), but is instead considered to be a moveable variable. Thus it is an error for any unsafe code to take the address of a local variable, value parameter, or parameter collection that has been captured by an anonymous function. *end note* The case of *unary_expression* designating a method group is described immediately below. @@ -895,7 +895,7 @@ fixed_pointer_initializer Each *fixed_pointer_declarator* declares a local variable of the given *pointer_type* and initializes that local variable with the address computed by the corresponding *fixed_pointer_initializer*. *pointer_type* shall not be *funcptr_type*. A local variable declared in a fixed statement is accessible in any *fixed_pointer_initializer*s occurring to the right of that variable’s declaration, and in the *embedded_statement* of the fixed statement. A local variable declared by a fixed statement is considered read-only. A compile-time error occurs if the embedded statement attempts to modify this local variable (via assignment or the `++` and `--` operators) or pass it as a reference or output parameter. -It is an error to use a captured local variable ([§12.22.6.2](expressions.md#122262-captured-outer-variables)), value parameter, or parameter array in a *fixed_pointer_initializer*. A *fixed_pointer_initializer* can be one of the following: +It is an error to use a captured local variable ([§12.22.6.2](expressions.md#122262-captured-outer-variables)), value parameter, or parameter collection in a *fixed_pointer_initializer*. A *fixed_pointer_initializer* can be one of the following: - The token “`&`” followed by a *variable_reference* ([§9.5](variables.md#95-variable-references)) to a moveable variable ([§24.4](unsafe-code.md#244-fixed-and-moveable-variables)) of a type `T`, provided the type `T*` is implicitly convertible to the pointer type given in the `fixed` statement. In this case, the initializer computes the address of the given variable, and the variable is guaranteed to remain at a fixed address for the duration of the fixed statement. If `T` is a managed type, a warning is produced. - An expression of an *array_type* with elements of a type `T`, provided the type `T*` is implicitly convertible to the pointer type given in the fixed statement. In this case, the initializer computes the address of the first element in the array, and the entire array is guaranteed to remain at a fixed address for the duration of the `fixed` statement. If the array expression is `null` or if the array has zero elements, the initializer computes an address equal to zero. If `T` is a managed type, a warning is produced.