diff --git a/standard/README.md b/standard/README.md index 91b573d5f..165963b07 100644 --- a/standard/README.md +++ b/standard/README.md @@ -163,6 +163,7 @@ - [§9.4.4.29](variables.md#94429--expressions) ?? expressions - [§9.4.4.30](variables.md#94430--expressions) ?: expressions - [§9.4.4.31](variables.md#94431-anonymous-functions) Anonymous functions + - [§9.4.4.32](variables.md#94432-rules-for-variables-in-local-functions) Rules for variables in local functions - [§9.5](variables.md#95-variable-references) Variable references - [§9.6](variables.md#96-atomicity-of-variable-references) Atomicity of variable references - [§10](conversions.md#10-conversions) Conversions @@ -398,6 +399,7 @@ - [§12.6.1](statements.md#1261-general) General - [§12.6.2](statements.md#1262-local-variable-declarations) Local variable declarations - [§12.6.3](statements.md#1263-local-constant-declarations) Local constant declarations + - [§12.6.4](statements.md#1264-local-function-declarations) Local function declarations - [§12.7](statements.md#127-expression-statements) Expression statements - [§12.8](statements.md#128-selection-statements) Selection statements - [§12.8.1](statements.md#1281-general) General diff --git a/standard/basic-concepts.md b/standard/basic-concepts.md index 5b238f23a..85e7299d3 100644 --- a/standard/basic-concepts.md +++ b/standard/basic-concepts.md @@ -222,7 +222,7 @@ The ***declared accessibility*** of a member can be one of the following: - Protected, which is selected by including a `protected` modifier in the member declaration. The intuitive meaning of `protected` is “access limited to the containing class or types derived from the containing class”. - Internal, which is selected by including an `internal` modifier in the member declaration. The intuitive meaning of `internal` is “access limited to this assembly”. - Protected internal, which is selected by including both a `protected` and an `internal` modifier in the member declaration. The intuitive meaning of `protected internal` is “accessible within this assembly as well as types derived from the containing class”. -- Private protected, which is selected by including both a `private` and a `protected` modifier in the member declaration. The intuitive meaning of `private protected` is "accessible within this assembly by the containing class and types derived from the containing class." +- Private protected, which is selected by including both a `private` and a `protected` modifier in the member declaration. The intuitive meaning of `private protected` is “accessible within this assembly by the containing class and types derived from the containing class.” - Private, which is selected by including a `private` modifier in the member declaration. The intuitive meaning of `private` is “access limited to the containing type”. Depending on the context in which a member declaration takes place, only certain types of declared accessibility are permitted. Furthermore, when a member declaration does not include any access modifiers, the context in which the declaration takes place determines the default declared accessibility. diff --git a/standard/grammar.md b/standard/grammar.md index aa83aac3f..b87ac0629 100644 --- a/standard/grammar.md +++ b/standard/grammar.md @@ -235,12 +235,17 @@ boolean_literal Integer_Literal : Decimal_Integer_Literal | Hexadecimal_Integer_Literal + | Binary_Integer_Literal ; fragment Decimal_Integer_Literal - : Decimal_Digit+ Integer_Type_Suffix? + : Decimal_Digit Decorated_Decimal_Digit* Integer_Type_Suffix? ; - + +fragment Decorated_Decimal_Digit + : '_'* Decimal_Digit + ; + fragment Decimal_Digit : '0'..'9' ; @@ -251,23 +256,40 @@ fragment Integer_Type_Suffix ; fragment Hexadecimal_Integer_Literal - : ('0x' | '0X') Hex_Digit+ Integer_Type_Suffix? + : ('0x' | '0X') Decorated_Hex_Digit+ Integer_Type_Suffix? ; +fragment Decorated_Hex_Digit + : '_'* Hex_Digit + ; + fragment Hex_Digit : '0'..'9' | 'A'..'F' | 'a'..'f' ; + +fragment Binary_Integer_Literal + : ('0b' | '0B') Decorated_Binary_Digit+ Integer_Type_Suffix? + ; + +fragment Decorated_Binary_Digit + : '_'* Binary_Digit + ; + +fragment Binary_Digit + : '0' | '1' + ; // Source: §6.4.5.4 Real literals Real_Literal - : Decimal_Digit+ '.' Decimal_Digit+ Exponent_Part? Real_Type_Suffix? - | '.' Decimal_Digit+ Exponent_Part? Real_Type_Suffix? - | Decimal_Digit+ Exponent_Part Real_Type_Suffix? - | Decimal_Digit+ Real_Type_Suffix + : Decimal_Digit Decorated_Decimal_Digit* '.' + Decimal_Digit Decorated_Decimal_Digit* Exponent_Part? Real_Type_Suffix? + | '.' Decimal_Digit Decorated_Decimal_Digit* Exponent_Part? Real_Type_Suffix? + | Decimal_Digit Decorated_Decimal_Digit* Exponent_Part Real_Type_Suffix? + | Decimal_Digit Decorated_Decimal_Digit* Real_Type_Suffix ; fragment Exponent_Part - : ('e' | 'E') Sign? Decimal_Digit+ + : ('e' | 'E') Sign? Decimal_Digit Decorated_Decimal_Digit* ; fragment Sign @@ -1024,8 +1046,8 @@ comma // Source: §11.7.17 The sizeof operator sizeof_expression - : 'sizeof' '(' unmanaged_type ')' - ; + : 'sizeof' '(' unmanaged_type ')' + ; // Source: §11.7.18 The checked and unchecked operators checked_expression @@ -1380,6 +1402,7 @@ labeled_statement declaration_statement : local_variable_declaration ';' | local_constant_declaration ';' + | local_function_declaration ; // Source: §12.6.2 Local variable declarations @@ -1421,6 +1444,26 @@ constant_declarator : identifier '=' constant_expression ; +// Source: §12.6.4 Local function declarations +local_function_declaration + : local_function_header local_function_body + ; + +local_function_header + : local_function_modifier* return_type identifier type_parameter_list? + ( formal_parameter_list? ) type_parameter_constraints_clause* + ; +local_function_modifier + : 'async' + | 'unsafe' + ; + +local_function_body + : block + | '=>' null_conditional_invocation_expression ';' + | '=>' expression ';' + ; + // Source: §12.7 Expression statements expression_statement : statement_expression ';' @@ -1555,7 +1598,7 @@ throw_statement // Source: §12.11 The try statement try_statement : 'try' block catch_clauses - | 'try' block catch_clauses* finally_clause + | 'try' block catch_clauses? finally_clause ; catch_clauses @@ -1683,10 +1726,10 @@ qualified_alias_member // Source: §14.2.1 General class_declaration - : attributes? class_modifier* 'partial'? 'class' identifier - type_parameter_list? class_base? type_parameter_constraints_clause* - class_body ';'? - ; + : attributes? class_modifier* 'partial'? 'class' identifier + type_parameter_list? class_base? type_parameter_constraints_clause* + class_body ';'? + ; // Source: §14.2.2.1 General class_modifier @@ -1703,24 +1746,24 @@ class_modifier // Source: §14.2.3 Type parameters type_parameter_list - : '<' type_parameters '>' + : '<' type_parameters '>' ; type_parameters - : attributes? type_parameter - | type_parameters ',' attributes? type_parameter - ; + : attributes? type_parameter + | type_parameters ',' attributes? type_parameter + ; // Source: §14.2.4.1 General class_base - : ':' class_type - | ':' interface_type_list - | ':' class_type ',' interface_type_list - ; + : ':' class_type + | ':' interface_type_list + | ':' class_type ',' interface_type_list + ; interface_type_list - : interface_type (',' interface_type)* - ; + : interface_type (',' interface_type)* + ; // Source: §14.2.5 Type parameter constraints type_parameter_constraints_clauses @@ -1761,8 +1804,8 @@ constructor_constraint // Source: §14.2.6 Class body class_body - : '{' class_member_declaration* '}' - ; + : '{' class_member_declaration* '}' + ; // Source: §14.3.1 General class_member_declaration @@ -1925,9 +1968,9 @@ property_initializer // Source: §14.7.3 Accessors accessor_declarations - : get_accessor_declaration set_accessor_declaration? - | set_accessor_declaration get_accessor_declaration? - ; + : get_accessor_declaration set_accessor_declaration? + | set_accessor_declaration get_accessor_declaration? + ; get_accessor_declaration : attributes? accessor_modifier? 'get' accessor_body @@ -1943,47 +1986,50 @@ accessor_modifier | 'private' | 'protected' 'internal' | 'internal' 'protected' + | 'protected' 'private' + | 'private' 'protected' ; accessor_body : block + | '=>' expression ';' | ';' ; // Source: §14.8.1 General event_declaration - : attributes? event_modifier* 'event' type variable_declarators ';' - | attributes? event_modifier* 'event' type member_name - '{' event_accessor_declarations '}' - ; + : attributes? event_modifier* 'event' type variable_declarators ';' + | attributes? event_modifier* 'event' type member_name + '{' event_accessor_declarations '}' + ; event_modifier - : 'new' - | 'public' - | 'protected' - | 'internal' - | 'private' - | 'static' - | 'virtual' - | 'sealed' - | 'override' - | 'abstract' - | 'extern' - | unsafe_modifier // unsafe code support - ; + : 'new' + | 'public' + | 'protected' + | 'internal' + | 'private' + | 'static' + | 'virtual' + | 'sealed' + | 'override' + | 'abstract' + | 'extern' + | unsafe_modifier // unsafe code support + ; event_accessor_declarations - : add_accessor_declaration remove_accessor_declaration - | remove_accessor_declaration add_accessor_declaration - ; + : add_accessor_declaration remove_accessor_declaration + | remove_accessor_declaration add_accessor_declaration + ; add_accessor_declaration - : attributes? 'add' block - ; + : attributes? 'add' block + ; remove_accessor_declaration - : attributes? 'remove' block - ; + : attributes? 'remove' block + ; // Source: §14.9 Indexers indexer_declaration @@ -1991,23 +2037,23 @@ indexer_declaration ; indexer_modifier - : 'new' - | 'public' - | 'protected' - | 'internal' - | 'private' - | 'virtual' - | 'sealed' - | 'override' - | 'abstract' - | 'extern' - | unsafe_modifier // unsafe code support - ; + : 'new' + | 'public' + | 'protected' + | 'internal' + | 'private' + | 'virtual' + | 'sealed' + | 'override' + | 'abstract' + | 'extern' + | unsafe_modifier // unsafe code support + ; indexer_declarator - : type 'this' '[' formal_parameter_list ']' - | type interface_type '.' 'this' '[' formal_parameter_list ']' - ; + : type 'this' '[' formal_parameter_list ']' + | type interface_type '.' 'this' '[' formal_parameter_list ']' + ; indexer_body : '{' accessor_declarations '}' @@ -2016,100 +2062,101 @@ indexer_body // Source: §14.10.1 General operator_declaration - : attributes? operator_modifier+ operator_declarator operator_body - ; + : attributes? operator_modifier+ operator_declarator operator_body + ; operator_modifier - : 'public' - | 'static' - | 'extern' - | unsafe_modifier // unsafe code support - ; + : 'public' + | 'static' + | 'extern' + | unsafe_modifier // unsafe code support + ; operator_declarator - : unary_operator_declarator - | binary_operator_declarator - | conversion_operator_declarator - ; + : unary_operator_declarator + | binary_operator_declarator + | conversion_operator_declarator + ; unary_operator_declarator - : type 'operator' overloadable_unary_operator '(' fixed_parameter ')' - ; + : type 'operator' overloadable_unary_operator '(' fixed_parameter ')' + ; overloadable_unary_operator - : '+' | '-' | '!' | '~' | '++' | '--' | 'true' | 'false' - ; + : '+' | '-' | '!' | '~' | '++' | '--' | 'true' | 'false' + ; binary_operator_declarator - : type 'operator' overloadable_binary_operator - '(' fixed_parameter ',' fixed_parameter ')' - ; + : type 'operator' overloadable_binary_operator + '(' fixed_parameter ',' fixed_parameter ')' + ; overloadable_binary_operator - : '+' | '-' | '*' | '/' | '%' | '&' | '|' | '^' | '<<' - | right_shift | '==' | '!=' | '>' | '<' | '>=' | '<=' - ; + : '+' | '-' | '*' | '/' | '%' | '&' | '|' | '^' | '<<' + | right_shift | '==' | '!=' | '>' | '<' | '>=' | '<=' + ; conversion_operator_declarator - : 'implicit' 'operator' type '(' fixed_parameter ')' - | 'explicit' 'operator' type '(' fixed_parameter ')' - ; + : 'implicit' 'operator' type '(' fixed_parameter ')' + | 'explicit' 'operator' type '(' fixed_parameter ')' + ; operator_body - : block - | '=>' expression ';' - | ';' - ; - + : block + | '=>' expression ';' + | ';' + ; // Source: §14.11.1 General constructor_declaration - : attributes? constructor_modifier* constructor_declarator constructor_body - ; + : attributes? constructor_modifier* constructor_declarator constructor_body + ; constructor_modifier - : 'public' - | 'protected' - | 'internal' - | 'private' - | 'extern' - | unsafe_modifier // unsafe code support - ; + : 'public' + | 'protected' + | 'internal' + | 'private' + | 'extern' + | unsafe_modifier // unsafe code support + ; constructor_declarator - : identifier '(' formal_parameter_list? ')' constructor_initializer? - ; + : identifier '(' formal_parameter_list? ')' constructor_initializer? + ; constructor_initializer - : ':' 'base' '(' argument_list? ')' - | ':' 'this' '(' argument_list? ')' - ; + : ':' 'base' '(' argument_list? ')' + | ':' 'this' '(' argument_list? ')' + ; constructor_body - : block - | ';' - ; + : block + | '=>' expression ';' + | ';' + ; // Source: §14.12 Static constructors static_constructor_declaration - : attributes? static_constructor_modifiers identifier '(' ')' - static_constructor_body - ; + : attributes? static_constructor_modifiers identifier '(' ')' + static_constructor_body + ; static_constructor_modifiers - : 'static' - | 'static' 'extern' unsafe_modifier? - | 'static' unsafe_modifier 'extern'? - | 'extern' 'static' unsafe_modifier? - | 'extern' unsafe_modifier 'static' - | unsafe_modifier 'static' 'extern'? - | unsafe_modifier 'extern' 'static' - ; + : 'static' + | 'static' 'extern' unsafe_modifier? + | 'static' unsafe_modifier 'extern'? + | 'extern' 'static' unsafe_modifier? + | 'extern' unsafe_modifier 'static' + | unsafe_modifier 'static' 'extern'? + | unsafe_modifier 'extern' 'static' + ; static_constructor_body - : block - | ';' - ; + : block + | '=>' expression ';' + | ';' + ; // Source: §14.13 Finalizers finalizer_declaration @@ -2122,13 +2169,14 @@ finalizer_declaration finalizer_body : block + | '=>' expression ';' | ';' ; // Source: §15.2.1 General struct_declaration - : attributes? struct_modifier* 'partial'? 'struct' identifier - type_parameter_list? struct_interfaces? + : attributes? struct_modifier* 'partial'? 'struct' + identifier type_parameter_list? struct_interfaces? type_parameter_constraints_clause* struct_body ';'? ; @@ -2139,6 +2187,7 @@ struct_modifier | 'protected' | 'internal' | 'private' + | 'readonly' | unsafe_modifier // unsafe code support ; @@ -2454,13 +2503,12 @@ fixed_pointer_initializer // Source: §22.8.2 Fixed-size buffer declarations fixed_size_buffer_declaration : attributes? fixed_size_buffer_modifier* 'fixed' buffer_element_type - fixed_size_buffer_declarator+ ';' + fixed_size_buffer_declarators ';' ; fixed_size_buffer_modifier : 'new' | 'public' - | 'protected' | 'internal' | 'private' | 'unsafe' @@ -2470,6 +2518,10 @@ buffer_element_type : type ; +fixed_size_buffer_declarators + : fixed_size_buffer_declarator (',' fixed_size_buffer_declarator)* + ; + fixed_size_buffer_declarator : identifier '[' constant_expression ']' ; diff --git a/standard/statements.md b/standard/statements.md index 1ecc414f5..011946391 100644 --- a/standard/statements.md +++ b/standard/statements.md @@ -280,7 +280,7 @@ declaration_statement ; ``` -A local variable is declared using a *local_variable_declaration* ([§12.6.2](statements.md#1262-local-variable-declarations)). A local constant is declared using a *local_constant_declaration* ([§12.6.3](statements.md#1263-local-constant-declarations)). A local function is declared using a *local_function_declaration* (§local-function-declarations-new-clause). +A local variable is declared using a *local_variable_declaration* ([§12.6.2](statements.md#1262-local-variable-declarations)). A local constant is declared using a *local_constant_declaration* ([§12.6.3](statements.md#1263-local-constant-declarations)). A local function is declared using a *local_function_declaration* ([§12.6.4](statements.md#1264-local-function-declarations)). ### 12.6.2 Local variable declarations @@ -417,7 +417,7 @@ The scope of a local constant is the block in which the declaration occurs. It i A local constant declaration that declares multiple constants is equivalent to multiple declarations of single constants with the same type. -### §local-function-declarations-new-clause Local function declarations +### 12.6.4 Local function declarations A *local_function_declaration* declares a local function. @@ -442,7 +442,7 @@ local_function_body ; ``` -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. (§14.6.1) +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. ([§14.6.1](classes.md#1461-general)) > *Example*: There are two common use cases for local functions: iterator methods and async methods. In iterator methods, any exceptions are observed only when calling code that enumerates the returned sequence. In async methods, any exceptions are only observed when the returned Task is awaited. The following example demonstrates separating parameter validation from the iterator implementation using a local function: > @@ -481,15 +481,15 @@ The *identifier* of a *local_function_declaration* must be unique in its declare A *local_function_declaration* may include one `async` ([§14.15](classes.md#1415-async-functions)) modifier and one `unsafe` ([§22.1](unsafe-code.md#221-general)) modifier. If the declaration includes the `async` modifier then the return type shall be `void` or a task type ([§14.15.1](classes.md#14151-general)). The `unsafe` modifier uses the containing lexical scope. The `async` modifier does not use the containing lexical scope. It is a compile-time error for *type_parameter_list* or *formal_parameter_list* to contain *attributes*. -A local function is declared at block scope, and that function may capture variables from the enclosing scope. It is a compile-time error if a captured variable is read by the body of the local function but is not definitely assigned before each call to the function. The compiler shall determine which variables are definitely assigned on return (§definite-assignment-rules-for-local-function). +A local function is declared at block scope, and that function may capture variables from the enclosing scope. It is a compile-time error if a captured variable is read by the body of the local function but is not definitely assigned before each call to the function. The compiler shall determine which variables are definitely assigned on return ([§9.4.4.32](variables.md#94432-rules-for-variables-in-local-functions)). -A local function may be called from a lexical point prior to its declaration. However, it is a compile-time error for the function to be declared lexically prior to the declaration of a variable used in the local function (§7.7). +A local function may be called from a lexical point prior to its declaration. However, it is a compile-time error for the function to be declared lexically prior to the declaration of a variable used in the local function ([§7.7](basic-concepts.md#77-scopes)). It is a compile-time error for a local function to declare a parameter or local variable with the same name as one declared in the enclosing scope. Local function bodies are always reachable. The endpoint of a local function declaration is reachable if the beginning point of the local function declaration is reachable. -> *Example*: In the following example, the body of `L` is reachable even though the beginning point of `L` is not reachable. Because the beginning point of `L` isn't reachable, the statement following the endpoint of `L` is not reachable: +> *Example*: In the following example, the body of `L` is reachable even though the beginning point of `L` is not reachable. Because the beginning point of `L` isn’t reachable, the statement following the endpoint of `L` is not reachable: > > ```csharp > class C @@ -507,7 +507,7 @@ Local function bodies are always reachable. The endpoint of a local function dec > } > ``` > -> In other words, the location of a local function declaration doesn't affect the reachability of any statements in the containing function. *end example* +> In other words, the location of a local function declaration doesn’t affect the reachability of any statements in the containing function. *end example* If the argument to a local function is dynamic, the function to be called must be resolved at compile time, not runtime. diff --git a/standard/variables.md b/standard/variables.md index 70bc75a60..7a07c96bf 100644 --- a/standard/variables.md +++ b/standard/variables.md @@ -802,7 +802,7 @@ For a *lambda_expression* or *anonymous_method_expression* *expr* with a body (e > > *end example* -#### §definite-assignment-rules-for-local-function Rules for variables in local functions +#### 9.4.4.32 Rules for variables in local functions Local functions are analyzed in the context of their parent method. There are two control flow paths that matter for local functions: function calls and delegate conversions.