From 2301cf2ef6618360988811c5abcba4c8d7aa9225 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Sun, 8 Feb 2026 14:41:52 -0500 Subject: [PATCH 1/9] support lambda improvements --- standard/lexical-structure.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/standard/lexical-structure.md b/standard/lexical-structure.md index 44b2fe53e..42be9b971 100644 --- a/standard/lexical-structure.md +++ b/standard/lexical-structure.md @@ -137,6 +137,22 @@ then the *type_argument_list* shall be retained as part of the disambiguated pro When recognising a *relational_expression* ([§12.15.1](expressions.md#12151-general)) if both the “*relational_expression* `is` *type*” and “*relational_expression* `is` *pattern*” alternatives are applicable, and *type* resolves to an accessible type, then the “*relational_expression* `is` *type*” alternative shall be chosen. +To differentiate a collection initializer ([§12.8.17.3.1](expressions.md#1281731-collection-initializers)) with an element assignment, from a collection initializer with a lambda expression, the parser shall look ahead. Consider the following: + +```csharp +var y = new C { [A] = x }; // OK: y[A] = x +var z = new C { [A] x => x }; // OK: z[0] = [A] x => x +``` + +The parser shall treat `?[` as the start of a *null_conditional_element_access* ([[§12.8.13](expressions.md#12813-null-conditional-element-access)): + +```csharp +x = b ? [A]; // OK +y = b ? [A] () => { } : z; // error +``` + +To differentiate a method call `T()` from a lambda expression `T () => e`, the parser shall look ahead. + ## 6.3 Lexical analysis ### 6.3.1 General From 0a4c8590c7e0dbb5317250a03658d8e3d33ff93f Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Sun, 8 Feb 2026 14:47:09 -0500 Subject: [PATCH 2/9] support lambda improvements --- standard/conversions.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/standard/conversions.md b/standard/conversions.md index 46e284b04..d59a034f6 100644 --- a/standard/conversions.md +++ b/standard/conversions.md @@ -405,6 +405,47 @@ For a *conditional_expression* `c ? e1 : e2`, when an implicit ***conditional expression conversion*** exists that permits an implicit conversion from *conditional_expression* to any type `T` for which there is a conversion-from-expression from `e1` to `T` and also from `e2` to `T`. It is an error if *conditional_expression* neither has a common type between `e1` and `e2` nor is subject to a conditional expression conversion. +### §anon-func-type-conversion Anonymous function type conversion + +The following conversions are permitted from an anonymous function type `F`(§anon-func-type): + +- To an anonymous function type `G` if the parameters and return types of `F` are variance-convertible to the parameters and return type of `G`. +- To `System.Delegate` or its base classes or interfaces. +- To `System.Linq.Expressions.Expression` or `System.Linq.Expressions.LambdaExpression`. + +There are no conversions to an anonymous function type from a type other than an anonymous function type. + +A conversion to `System.Delegate` or its base classes or interfaces realizes the anonymous function or method group as an instance of an appropriate delegate type. + +A conversion to `System.Linq.Expressions.Expression` or its base classes realizes the anonymous function or method group as an expression tree with an appropriate delegate type. + +> *Example*: +> +> +> ```csharp +> Delegate d = delegate (object obj) { }; // Action +> Expression e = () => ""; // Expression> +> object o = "".Clone; // Func +> ``` +> +> *end example* + +Anonymous function type conversions are not implicit or explicit standard conversions and are not considered when determining whether a user-defined conversion operator is applicable to an anonymous function or method group. + +Although an implicit conversion to `object` is permitted, a warning shall be issued, as this may have been unintentional. + +> *Example*: +> +> +> ```csharp +> Random r = new Random(); +> object obj; +> obj = r.NextDouble; // warning: was this intentional? +> obj = (object)r.NextDouble; // ok +> ``` +> +> *end example* + ## 10.3 Explicit conversions ### 10.3.1 General From 5110efc7eda97ac689dceaaece09627cca3abb3a Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Sun, 8 Feb 2026 14:50:21 -0500 Subject: [PATCH 3/9] support lambda improvements --- standard/statements.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/standard/statements.md b/standard/statements.md index fe486c86d..28111c326 100644 --- a/standard/statements.md +++ b/standard/statements.md @@ -405,6 +405,24 @@ An *implicitly_typed_local_variable_declaration* introduces a single local varia > > *end example* +Anonymous functions and method groups with anonymous function types may be used as initializers in an *implicitly_typed_local_variable_declaration*. + +Anonymous functions and method groups with anonymous function types may not be used in contexts in which the target is a discard. + +> *Example*: +> +> +> ```csharp +> var f1 = () => default; // error: cannot infer type +> var f2 = x => x; // error: cannot infer type +> var f3 = () => 1; // Func +> var f4 = string () => "xx"; // Func +> var f5 = delegate (object o) { }; // Action +> _ = () => 1; // error +> ``` +> +> *end example* + #### 13.6.2.3 Explicitly typed local variable declarations ```ANTLR From 3dc71657dfcd5bf69562c9429cd33b61d72cfb71 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Sun, 8 Feb 2026 15:17:42 -0500 Subject: [PATCH 4/9] support lambda improvements --- standard/expressions.md | 109 +++++++++++++++++++++++++++++++++++----- 1 file changed, 96 insertions(+), 13 deletions(-) diff --git a/standard/expressions.md b/standard/expressions.md index d5bf99b47..57330a96f 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -807,7 +807,7 @@ An *unfixed* type variable `Xᵢ` *depends directly on* an *unfixed* type varia An *input type inference* is made *from* an expression `E` *to* a type `T` in the following way: - If `E` is a tuple expression ([§12.8.6](expressions.md#1286-tuple-expressions)) with arity `N` and elements `Eᵢ`, and `T` is a tuple type with arity `N` with corresponding element types `Tₑ` or `T` is a nullable value type `T0?` and `T0` is a tuple type with arity `N` that has a corresponding element type `Tₑ`, then for each `Eᵢ`, an input type inference is made from `Eᵢ` to `Tₑ`. -- If `E` is an anonymous function, an *explicit parameter type inference* ([§12.6.3.9](expressions.md#12639-explicit-parameter-type-inferences)) is made *from* `E` *to* `T` +- If `E` is an anonymous function and `T` is a delegate type or expression tree type, an *explicit parameter type inference* ([§12.6.3.9](expressions.md#12639-explicit-parameter-type-inferences)) is made *from* `E` *to* `T` and an *explicit return type inference* is made from `E` to `T`. - Otherwise, if `E` has a type `U` and the corresponding parameter is a value parameter ([§15.6.2.2](classes.md#15622-value-parameters)) then a *lower-bound inference* ([§12.6.3.11](expressions.md#126311-lower-bound-inferences)) is made *from* `U` *to* `T`. - Otherwise, if `E` has a type `U` and the corresponding parameter is a reference parameter ([§15.6.2.3.3](classes.md#156233-reference-parameters)), or output parameter ([§15.6.2.3.4](classes.md#156234-output-parameters)) then an *exact inference* ([§12.6.3.10](expressions.md#126310-exact-inferences)) is made *from* `U` *to* `T`. - Otherwise, if `E` has a type `U` and the corresponding parameter is an input parameter ([§15.6.2.3.2](classes.md#156232-input-parameters)) and `E` is an input argument, then an *exact inference* ([§12.6.3.10](expressions.md#126310-exact-inferences)) is made *from* `U` *to* `T`. @@ -819,7 +819,7 @@ An *input type inference* is made *from* an expression `E` *to* a type `T` in th An *output type inference* is made *from* an expression `E` *to* a type `T` in the following way: - If `E` is a tuple expression with arity `N` and elements `Eᵢ`, and `T` is a tuple type with arity `N` with corresponding element types `Tₑ` or `T` is a nullable value type `T0?` and `T0` is a tuple type with arity `N` that has a corresponding element type `Tₑ`, then for each `Eᵢ` an output type inference is made from `Eᵢ` to `Tₑ`. -- If `E` is an anonymous function with inferred return type `U` ([§12.6.3.14](expressions.md#126314-inferred-return-type)) and `T` is a delegate type or expression tree type with return type `Tₓ`, then a *lower-bound inference* ([§12.6.3.11](expressions.md#126311-lower-bound-inferences)) is made *from* `U` *to* `Tₓ`. +- **TBD** If `E` is an anonymous function with inferred return type `U` ([§12.6.3.14](expressions.md#126314-inferred-return-type)) and `T` is a delegate type or expression tree type with return type `Tₓ`, then a *lower-bound inference* ([§12.6.3.11](expressions.md#126311-lower-bound-inferences)) is made *from* `U` *to* `Tₓ`. - Otherwise, if `E` is a method group and `T` is a delegate type or expression tree type with parameter types `T₁...Tᵥ` and return type `Tₓ`, and overload resolution of `E` with the types `T₁...Tᵥ` yields a single method with return type `U`, then a *lower-bound inference* is made *from* `U` *to* `Tₓ`. - If `E` is an address-of method group and `T` is a function pointer type ([§24.3.3](unsafe-code.md#2433-function-pointers)) then with parameter types `T1..Tk` and return type `Tb`, and overload resolution of `E` with the types `T1..Tk` yields a single method with return type `U`, then a *lower-bound inference* is made from `U` to `Tb`. > *Note*: This is only applicable in unsafe code. *end note* @@ -910,7 +910,7 @@ An *upper-bound inference from* a type `U` *to* a type `V` is made as follows: An *unfixed* type variable `Xᵢ` with a set of bounds is *fixed* as follows: -- The set of *candidate types* `Uₑ` starts out as the set of all types in the set of bounds for `Xᵢ`. +- The set of *candidate types* `Uₑ` starts out as the set of all types in the set of bounds for `Xᵢ` where function types are ignored in lower bounds if there are any types that are not function types. - Each bound for `Xᵢ` is examined in turn: For each exact bound U of `Xᵢ` all types `Uₑ` that are not identical to `U` are removed from the candidate set. For each lower bound `U` of `Xᵢ` all types `Uₑ` to which there is *not* an implicit conversion from `U` are removed from the candidate set. For each upper-bound U of `Xᵢ` all types `Uₑ` from which there is *not* an implicit conversion to `U` are removed from the candidate set. - If among the remaining candidate types `Uₑ` there is a unique type `V` to which there is an implicit conversion from all the other candidate types, then `Xᵢ` is fixed to `V`. - Otherwise, type inference fails. @@ -996,6 +996,12 @@ The ***inferred return type*** is determined as follows: > > *end example* +#### §exprettypeinf Explicit return type inference + +An *explicit return type inference* is made *from* an expression `E` *to* a type `T` in the following way: + +- If `E` is an anonymous function with explicit return type `Uᵣ`, and `T` is a delegate type or expression tree type with return type `Vᵣ`, then an *exact inference* ([§12.6.3.10](expressions.md#126310-exact-inferences) is made *from* `Uᵣ` *to* `Vᵣ`. + #### 12.6.3.15 Type inference for conversion of method groups Similar to calls of generic methods, type inference shall also be applied when a method group `M` containing a generic method is converted to a given delegate type `D` ([§10.8](conversions.md#108-method-group-conversions)). Given a method @@ -1014,6 +1020,8 @@ Instead, all `Xᵢ` are considered *unfixed*, and a *lower-bound inference* is #### 12.6.3.16 Finding the best common type of a set of expressions +**TBD** + In some cases, a common type needs to be inferred for a set of expressions. In particular, the element types of implicitly typed arrays and the return types of anonymous functions with *block* bodies are found in this way. The best common type for a set of expressions `E₁...Eᵥ` is determined as follows: @@ -1021,7 +1029,7 @@ The best common type for a set of expressions `E₁...Eᵥ` is determined as fol - A new *unfixed* type variable `X` is introduced. - For each expression `Ei` an *output type inference* ([§12.6.3.8](expressions.md#12638-output-type-inferences)) is performed from it to `X`. - `X` is *fixed* ([§12.6.3.13](expressions.md#126313-fixing)), if possible, and the resulting type is the best common type. -- Otherwise inference fails. +- Otherwise; inference fails. > *Note*: Intuitively this inference is equivalent to calling a method `void M(X x₁ ... X xᵥ)` with the `Eᵢ` as arguments and inferring `X`. *end note* @@ -1112,8 +1120,10 @@ Parameter lists for each of the candidate function members are constructed in th 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 `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ᵥ`. +1. for each argument, the implicit conversion from `Eᵥ` to `Pᵥ` is not a _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 a _function_type_, and + - for at least one argument, the implicit conversion from `Eᵥ` to `Qᵥ` is a _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 a _function_type_, or +1. 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. @@ -1151,6 +1161,7 @@ Given `int i = 10;`, according to [§12.6.4.2](expressions.md#12642-applicable-f Given an implicit conversion `C₁` that converts from an expression `E` to a type `T₁`, and an implicit conversion `C₂` that converts from an expression `E` to a type `T₂`, `C₁` is a ***better conversion*** than `C₂` if `E` does not exactly match `T₂` and at least one of the following holds: +- `C1` is not a _function_type_conversion_ and `C2` is a _function_type_conversion_, or - `E` exactly matches `T₁` and `E` does not exactly match `T₂` ([§12.6.4.6](expressions.md#12646-exactly-matching-expression)) - `C₁` is not a conditional expression conversion and `C₂` is a conditional expression conversion. - `E` exactly matches both or neither of `T₁` and `T₂`, and `T₁` is a better conversion target than `T₂` ([§12.6.4.7](expressions.md#12647-better-conversion-target)) and either `C₁` and `C₂` are both conditional expression conversions or neither is a conditional expression conversion. @@ -5379,11 +5390,13 @@ The run-time processing of a conditional expression of the form `b ? x : y` An ***anonymous function*** is an expression that represents an “in-line” method definition. An anonymous function does not have a value or type in and of itself, but is convertible to a compatible delegate or expression-tree type. The evaluation of an anonymous-function conversion depends on the target type of the conversion: If it is a delegate type, the conversion evaluates to a delegate value referencing the method that the anonymous function defines. If it is an expression-tree type, the conversion evaluates to an expression tree that represents the structure of the method as an object structure. -> *Note*: For historical reasons, there are two syntactic flavors of anonymous functions, namely *lambda_expression*s and *anonymous_method_expression*s. For almost all purposes, *lambda_expression*s are more concise and expressive than *anonymous_method_expression*s, which remain in the language for backwards compatibility. *end note* +> *Note*: For historical reasons, there are two syntactic flavors of anonymous functions, namely *lambda_expression* and *anonymous_method_expression*. For almost all purposes, *lambda_expression* is more concise and expressive than *anonymous_method_expression*s, which remain in the language for backwards compatibility. *end note* ```ANTLR lambda_expression - : anonymous_function_modifier? anonymous_function_signature '=>' anonymous_function_body + : attributes? anonymous_function_modifier? + (return_type | ref_kind ref_return_type)? + anonymous_function_signature '=>' anonymous_function_body ; anonymous_method_expression @@ -5410,7 +5423,7 @@ explicit_anonymous_function_parameter_list ; explicit_anonymous_function_parameter - : anonymous_function_parameter_modifier? type identifier + : attributes? anonymous_function_parameter_modifier? type identifier ; anonymous_function_parameter_modifier @@ -5430,7 +5443,7 @@ implicit_anonymous_function_parameter_list ; implicit_anonymous_function_parameter - : identifier + : attributes? identifier ; anonymous_function_body @@ -5470,11 +5483,13 @@ When recognising an *anonymous_function_body* if both the *null_conditional_invo The `=>` operator has the same precedence as assignment (`=`) and is right-associative. +> *Note*: It can be deduced from [§23.5.3.2](attributes.md#23532-conditional-methods) that *attributes* in a *lambda_expression* cannot designate that expression as a conditional method. *end note* + An anonymous function with the `async` modifier is an async function and follows the rules described in [§15.14](classes.md#1514-async-functions). The parameters of an anonymous function in the form of a *lambda_expression* can be explicitly or implicitly typed. In an explicitly typed parameter list, the type of each parameter is explicitly stated. In an implicitly typed parameter list, the types of the parameters are inferred from the context in which the anonymous function occurs—specifically, when the anonymous function is converted to a compatible delegate type or expression tree type, that type provides the parameter types ([§10.7](conversions.md#107-anonymous-function-conversions)). -In a *lambda_expression* with a single, implicitly typed parameter, the parentheses may be omitted from the parameter list. In other words, an anonymous function of the form +In a *lambda_expression* with a single, implicitly typed parameter, the parentheses may be omitted from the parameter list, provided that *lambda_expression* has no *attributes* on the whole expression or on any of its *explicit_anonymous_function_parameter*s, and it has no explicit return type. In other words, an anonymous function of the form ```csharp ( «param» ) => «expr» @@ -5488,6 +5503,8 @@ can be abbreviated to The parameter list of an anonymous function in the form of an *anonymous_method_expression* is optional. If given, the parameters shall be explicitly typed. If not, the anonymous function is convertible to a delegate with any parameter list not containing output parameters. +It is a compile error for any *explicit_anonymous_function_parameter* of an anonymous function in the form of an *anonymous_method_expression* to have *attributes*. + A *block* body of an anonymous function is always reachable ([§13.2](statements.md#132-end-points-and-reachability)). > *Example*: Some examples of anonymous functions follow below: @@ -5502,6 +5519,9 @@ A *block* body of an anonymous function is always reachable ([§13.2](statements > async (t1,t2) => await t1 + await t2 // Async > static delegate (int x) { return x + 1; } // Anonymous method expression > delegate { return 1 + 1; } // Parameter list omitted +> var concat = string ([DisallowNull] string a, [DisallowNull] string b) => a + b; +> Func parse = [X][return: Y] ([Z] s) +> => (s is not null) ? int.Parse(s) : null; > ``` > > *end example* @@ -5512,16 +5532,17 @@ The behavior of *lambda_expression*s and *anonymous_method_expression*s is the s - *lambda_expression*s permit parameter types to be omitted and inferred whereas *anonymous_method_expression*s require parameter types to be explicitly stated. - The body of a *lambda_expression* can be an expression or a block whereas the body of an *anonymous_method_expression* shall be a block. - Only *lambda_expression*s have conversions to compatible expression tree types ([§8.6](types.md#86-expression-tree-types)). +- Only *lambda_expression*s may have *attributes* and explicit return types. ### 12.22.2 Anonymous function signatures If an *explicit_anonymous_function_parameter_list* or an *implicit_anonymous_function_parameter_list* contains multiple *identifier*s `_`, each of those identifiers denotes a discard ([§9.2.9.2](variables.md#9292-discards)). Otherwise, any single *identifier* `_` denotes a parameter. -The *anonymous_function_signature* of an anonymous function defines the names and optionally the types of the parameters for the anonymous function. The scope of the parameters of the anonymous function is the *anonymous_function_body* ([§7.7](basic-concepts.md#77-scopes)). Together with the parameter list (if given) the anonymous-method-body constitutes a declaration space ([§7.3](basic-concepts.md#73-declarations)). It is thus a compile-time error for the name of a parameter of the anonymous function to match the name of a local variable, local constant or parameter whose scope includes the *anonymous_method_expression* or *lambda_expression*. +The *anonymous_function_signature* of an anonymous function defines the names and optionally the types and *attributes* of the parameters for the anonymous function. The scope of the parameters of the anonymous function is the *anonymous_function_body* ([§7.7](basic-concepts.md#77-scopes)). Together with the parameter list (if given) the anonymous-method-body constitutes a declaration space ([§7.3](basic-concepts.md#73-declarations)). It is thus a compile-time error for the name of a parameter of the anonymous function to match the name of a local variable, local constant or parameter whose scope includes the *anonymous_method_expression* or *lambda_expression*. If an anonymous function has an *explicit_anonymous_function_signature*, then the set of compatible delegate types and expression tree types is restricted to those that have the same parameter types and modifiers in the same order ([§10.7](conversions.md#107-anonymous-function-conversions)). In contrast to method group conversions ([§10.8](conversions.md#108-method-group-conversions)), contra-variance of anonymous function parameter types is not supported. If an anonymous function does not have an *anonymous_function_signature*, then the set of compatible delegate types and expression tree types is restricted to those that have no output parameters. -Note that an *anonymous_function_signature* cannot include attributes or a parameter array. Nevertheless, an *anonymous_function_signature* may be compatible with a delegate type whose parameter list contains a parameter array. +Note that an *anonymous_function_signature* cannot include a parameter array. Nevertheless, an *anonymous_function_signature* may be compatible with a delegate type whose parameter list contains a parameter array. Note also that conversion to an expression tree type, even if compatible, may still fail at compile-time ([§8.6](types.md#86-expression-tree-types)). @@ -5886,6 +5907,68 @@ Separate non-`static` anonymous functions can capture the same instance of an ou An anonymous function `F` shall always be converted to a delegate type `D` or an expression-tree type `E`, either directly or through the execution of a delegate creation expression `new D(F)`. This conversion determines the result of the anonymous function, as described in [§10.7](conversions.md#107-anonymous-function-conversions). +### §anon-func-type Anonymous function type + +When an anonymous function expression is converted (§anon-func-type-conversion) to a delegate or `Expression` type ([§8.6](types.md#86-expression-tree-types)), that anonymous function expression is said to have a ***natural type***. However, for that to be permitted, sufficient information needs to be provided or inferred. Consider the following: + +```csharp +var parse1 = (string s) => int.Parse(s); +var parse2 = delegate (string s) { return int.Parse(s); }; +``` + +In both cases, the type of the target can be inferred as `Func`, allowing `var` to be used instead. The compiler chooses an available `Func` or `Action` delegate, if a suitable one exists; otherwise, it synthesizes a delegate type (which shall be done if there are any ref parameters). + +Not all anonymous function expressions have a natural type, however. Consider the following: + +```csharp +var parse3 = s => int.Parse(s); // error: type could not be inferred +``` + +An anonymous function expression has a natural type if the parameter types are explicit, and the return type is either explicit or can be inferred. + +An anonymous function expression having a natural type may be used in the context of a less-explicit type: + +```csharp +object parse4 = (string s) => int.Parse(s); +Delegate parse5 = (string s) => int.Parse(s); +``` + +A method group has a natural type if all candidate methods (including extension methods) in the method group have a common signature. + +```csharp +var read = Console.Read; // Just one overload; Func inferred +var write = Console.Write; // error: multiple overloads, can't choose +``` + +If an anonymous function expression is used in the context of a `LambdaExpression` or `Expression`, and the anonymous function expression has a natural delegate type, the resulting expression has the natural type of `Expression` with the natural delegate type used as the argument for the type parameter: + +```csharp +LambdaExpression parseExpr = (string s) => int.Parse(s); + // Expression> +Expression parseExpr = (string s) => int.Parse(s); + // Expression> +``` + +The natural type of an anonymous function expression or method group is called an ***anonymous function type***. An anonymous function type represents a method signature: the parameter types and ref kinds, and the return type and ref kind. Anonymous function expressions or method groups with the same signature have the same anonymous function type. + +Anonymous function types are used in a few specific contexts only: + +- Implicit and explicit conversions. +- Method type inference ([§12.6.3](expressions.md#1263-type-inference)) and best common type ([§12.6.3.16](expressions.md#126316-finding-the-best-common-type-of-a-set-of-expressions)). +- The initializer *expression* in an *implicitly_typed_local_variable_declarator* ([§13.6.2.2](statements.md#13622-implicitly-typed-local-variable-declarations)). + +An anonymous function type exists only at compile time. + +The delegate type for the anonymous function or method group with parameter types `P1, ..., Pn` and return type `R` is, as follows: + +- If any parameter or return value is not by value, or there are more than 16 parameters, or any of the parameter types or return type are not valid type arguments (e.g., `(int* p) => { }`), then the delegate is a synthesized `internal` anonymous delegate type with a signature that matches the anonymous function or method group, and with parameter names `arg1, ..., argn`, or `arg` if a single parameter; +- If `R` is `void`, then the delegate type is `System.Action`; +- Otherwise, the delegate type is `System.Func`. + +> *Note*: A future eversion of this specification might allow more signatures to bind to `System.Action<>` and `System.Func<>` types (e.g., if `ref struct` types are allowed type arguments).*end note* + +If two anonymous functions or method groups in the same compilation require synthesized delegate types with the same parameter types and modifiers, and the same return type and modifiers, the compiler shall use the same synthesized delegate type. + ### 12.22.8 Implementation Example **This subclause is informative.** From 6dd6373690a3adaaa57ffa0eba7ff69cf52dc7be Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Sun, 8 Feb 2026 15:45:08 -0500 Subject: [PATCH 5/9] fix test example name --- standard/statements.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standard/statements.md b/standard/statements.md index 28111c326..bc26591d2 100644 --- a/standard/statements.md +++ b/standard/statements.md @@ -411,7 +411,7 @@ Anonymous functions and method groups with anonymous function types may not be u > *Example*: > -> +> > ```csharp > var f1 = () => default; // error: cannot infer type > var f2 = x => x; // error: cannot infer type From fb4f5b383d1a7e1d47728e8b51217799b21e6647 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Sun, 8 Feb 2026 15:55:00 -0500 Subject: [PATCH 6/9] fix formatting --- standard/expressions.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/standard/expressions.md b/standard/expressions.md index 57330a96f..35f82274a 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -1120,9 +1120,10 @@ Parameter lists for each of the candidate function members are constructed in th 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 -1. for each argument, the implicit conversion from `Eᵥ` to `Pᵥ` is not a _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 a _function_type_, and - - for at least one argument, the implicit conversion from `Eᵥ` to `Qᵥ` is a _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 a _function_type_, or +1. for each argument, the implicit conversion from `Eᵥ` to `Pᵥ` is not a *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 a *function_type*, and + - for at least one argument, the implicit conversion from `Eᵥ` to `Qᵥ` is a *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 a *function_type*, or 1. 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. @@ -1161,7 +1162,7 @@ Given `int i = 10;`, according to [§12.6.4.2](expressions.md#12642-applicable-f Given an implicit conversion `C₁` that converts from an expression `E` to a type `T₁`, and an implicit conversion `C₂` that converts from an expression `E` to a type `T₂`, `C₁` is a ***better conversion*** than `C₂` if `E` does not exactly match `T₂` and at least one of the following holds: -- `C1` is not a _function_type_conversion_ and `C2` is a _function_type_conversion_, or +- `C1` is not a *function_type_conversion* and `C2` is a *function_type_conversion*, or - `E` exactly matches `T₁` and `E` does not exactly match `T₂` ([§12.6.4.6](expressions.md#12646-exactly-matching-expression)) - `C₁` is not a conditional expression conversion and `C₂` is a conditional expression conversion. - `E` exactly matches both or neither of `T₁` and `T₂`, and `T₁` is a better conversion target than `T₂` ([§12.6.4.7](expressions.md#12647-better-conversion-target)) and either `C₁` and `C₂` are both conditional expression conversions or neither is a conditional expression conversion. From 539f8b2ea5e9829a42e7ff3ed92cf663d837a83d Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Sun, 8 Feb 2026 15:58:21 -0500 Subject: [PATCH 7/9] fix formatting --- standard/expressions.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/standard/expressions.md b/standard/expressions.md index 35f82274a..cd7791817 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -1120,11 +1120,12 @@ Parameter lists for each of the candidate function members are constructed in th 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 -1. for each argument, the implicit conversion from `Eᵥ` to `Pᵥ` is not a *function_type_conversion*, and +- for each argument, the implicit conversion from `Eᵥ` to `Pᵥ` is not a *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 a *function_type*, and - for at least one argument, the implicit conversion from `Eᵥ` to `Qᵥ` is a *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 a *function_type*, or -1. 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. From 00e4d9d249360f544d62071428b2fb9891f5bc86 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Fri, 27 Mar 2026 17:04:21 -0400 Subject: [PATCH 8/9] Address open comments in PR - ** Delete `**TBD** ` from the bullet in output type inference, leaving the rest unchanged. - ** Delete the `**TBD**` line from best common type and the blank line after it. - ** Restructure the paragraph in better conversion from expression. - Replace all remaining `function_type` / `function_type_conversion` with "anonymous function type" / "anonymous function type conversion" to match the naming in the new sections. --- standard/expressions.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/standard/expressions.md b/standard/expressions.md index cd7791817..46025c131 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -819,7 +819,7 @@ An *input type inference* is made *from* an expression `E` *to* a type `T` in th An *output type inference* is made *from* an expression `E` *to* a type `T` in the following way: - If `E` is a tuple expression with arity `N` and elements `Eᵢ`, and `T` is a tuple type with arity `N` with corresponding element types `Tₑ` or `T` is a nullable value type `T0?` and `T0` is a tuple type with arity `N` that has a corresponding element type `Tₑ`, then for each `Eᵢ` an output type inference is made from `Eᵢ` to `Tₑ`. -- **TBD** If `E` is an anonymous function with inferred return type `U` ([§12.6.3.14](expressions.md#126314-inferred-return-type)) and `T` is a delegate type or expression tree type with return type `Tₓ`, then a *lower-bound inference* ([§12.6.3.11](expressions.md#126311-lower-bound-inferences)) is made *from* `U` *to* `Tₓ`. +- If `E` is an anonymous function with inferred return type `U` ([§12.6.3.14](expressions.md#126314-inferred-return-type)) and `T` is a delegate type or expression tree type with return type `Tₓ`, then a *lower-bound inference* ([§12.6.3.11](expressions.md#126311-lower-bound-inferences)) is made *from* `U` *to* `Tₓ`. - Otherwise, if `E` is a method group and `T` is a delegate type or expression tree type with parameter types `T₁...Tᵥ` and return type `Tₓ`, and overload resolution of `E` with the types `T₁...Tᵥ` yields a single method with return type `U`, then a *lower-bound inference* is made *from* `U` *to* `Tₓ`. - If `E` is an address-of method group and `T` is a function pointer type ([§24.3.3](unsafe-code.md#2433-function-pointers)) then with parameter types `T1..Tk` and return type `Tb`, and overload resolution of `E` with the types `T1..Tk` yields a single method with return type `U`, then a *lower-bound inference* is made from `U` to `Tb`. > *Note*: This is only applicable in unsafe code. *end note* @@ -1020,8 +1020,6 @@ Instead, all `Xᵢ` are considered *unfixed*, and a *lower-bound inference* is #### 12.6.3.16 Finding the best common type of a set of expressions -**TBD** - In some cases, a common type needs to be inferred for a set of expressions. In particular, the element types of implicitly typed arrays and the return types of anonymous functions with *block* bodies are found in this way. The best common type for a set of expressions `E₁...Eᵥ` is determined as follows: @@ -1161,12 +1159,13 @@ Given `int i = 10;`, according to [§12.6.4.2](expressions.md#12642-applicable-f #### 12.6.4.5 Better conversion from expression -Given an implicit conversion `C₁` that converts from an expression `E` to a type `T₁`, and an implicit conversion `C₂` that converts from an expression `E` to a type `T₂`, `C₁` is a ***better conversion*** than `C₂` if `E` does not exactly match `T₂` and at least one of the following holds: +Given an implicit conversion `C₁` that converts from an expression `E` to a type `T₁`, and an implicit conversion `C₂` that converts from an expression `E` to a type `T₂`, `C₁` is a ***better conversion*** than `C₂` if: -- `C1` is not a *function_type_conversion* and `C2` is a *function_type_conversion*, or -- `E` exactly matches `T₁` and `E` does not exactly match `T₂` ([§12.6.4.6](expressions.md#12646-exactly-matching-expression)) -- `C₁` is not a conditional expression conversion and `C₂` is a conditional expression conversion. -- `E` exactly matches both or neither of `T₁` and `T₂`, and `T₁` is a better conversion target than `T₂` ([§12.6.4.7](expressions.md#12647-better-conversion-target)) and either `C₁` and `C₂` are both conditional expression conversions or neither is a conditional expression conversion. +- `C₁` is not an anonymous function type conversion and `C₂` is an anonymous function type conversion, or +- `E` does not exactly match `T₂` and at least one of the following holds: + - `E` exactly matches `T₁` and `E` does not exactly match `T₂` ([§12.6.4.6](expressions.md#12646-exactly-matching-expression)) + - `C₁` is not a conditional expression conversion and `C₂` is a conditional expression conversion. + - `E` exactly matches both or neither of `T₁` and `T₂`, and `T₁` is a better conversion target than `T₂` ([§12.6.4.7](expressions.md#12647-better-conversion-target)) and either `C₁` and `C₂` are both conditional expression conversions or neither is a conditional expression conversion. - `V` is a function pointer type `delegate*` and `U` is a function pointer type `delegate*`, and the calling convention of `V` is identical to `U`, and the refness of `Vi` is identical to `Ui`. > *Note*: This is only applicable in unsafe code. *end note* - `E` is a method group ([§12.2](expressions.md#122-expression-classifications)), `T₁` is compatible ([§21.4](delegates.md#214-delegate-compatibility)) with the single best method from the method group for conversion `C₁`, and `T₂` is not compatible with the single best method from the method group for conversion `C₂` From 73e715374e16c72678ad053455a219759594a16f Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Fri, 27 Mar 2026 17:37:53 -0400 Subject: [PATCH 9/9] Add omissions from this PR Add various omissions from the lambda improvements. --- standard/attributes.md | 9 ++++++--- standard/conversions.md | 4 +++- standard/expressions.md | 16 +++++++++------- standard/statements.md | 2 +- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/standard/attributes.md b/standard/attributes.md index 8ab493677..28416371c 100644 --- a/standard/attributes.md +++ b/standard/attributes.md @@ -156,7 +156,7 @@ The types of positional and named parameters for an attribute class are limited ## 23.3 Attribute specification -Application of a previously defined attribute to a program entity is called ***attribute specification***. An attribute is a piece of additional declarative information that is specified for a program entity. Attributes can be specified at global scope (to specify attributes on the containing assembly or module) and for *type_declaration*s ([§14.7](namespaces.md#147-type-declarations)), *class_member_declaration*s ([§15.3](classes.md#153-class-members)), *interface_member_declaration*s ([§19.4](interfaces.md#194-interface-members)), *struct_member_declaration*s ([§16.3](structs.md#163-struct-members)), *enum_member_declaration*s ([§20.2](enums.md#202-enum-declarations)), *accessor_declaration*s ([§15.7.3](classes.md#1573-accessors)), *event_accessor_declaration*s ([§15.8](classes.md#158-events)), elements of *parameter_list*s ([§15.6.2](classes.md#1562-method-parameters)), and elements of *type_parameter_list*s ([§15.2.3](classes.md#1523-type-parameters)). +Application of a previously defined attribute to a program entity is called ***attribute specification***. An attribute is a piece of additional declarative information that is specified for a program entity. Attributes can be specified at global scope (to specify attributes on the containing assembly or module) and for *type_declaration*s ([§14.7](namespaces.md#147-type-declarations)), *class_member_declaration*s ([§15.3](classes.md#153-class-members)), *interface_member_declaration*s ([§19.4](interfaces.md#194-interface-members)), *struct_member_declaration*s ([§16.3](structs.md#163-struct-members)), *enum_member_declaration*s ([§20.2](enums.md#202-enum-declarations)), *accessor_declaration*s ([§15.7.3](classes.md#1573-accessors)), *event_accessor_declaration*s ([§15.8](classes.md#158-events)), elements of *parameter_list*s ([§15.6.2](classes.md#1562-method-parameters)), elements of *type_parameter_list*s ([§15.2.3](classes.md#1523-type-parameters)), *lambda_expression*s ([§12.22.1](expressions.md#12221-general)), and elements of *explicit_anonymous_function_parameter*s and *implicit_anonymous_function_parameter*s ([§12.22.1](expressions.md#12221-general)). Attributes are specified in ***attribute section***s. An attribute section consists of a pair of square brackets, which surround a comma-separated list of one or more attributes. The order in which attributes are specified in such a list, and the order in which sections attached to the same program entity are arranged, is not significant. For instance, the attribute specifications `[A][B]`, `[B][A]`, `[A, B]`, and `[B, A]` are equivalent. @@ -252,10 +252,10 @@ The standardized *attribute_target* names are `event`, `field`, `method`, `param - `event` — an event. - `field` — a field. A field-like event (i.e., one without accessors) ([§15.8.2](classes.md#1582-field-like-events)) and an automatically implemented property ([§15.7.4](classes.md#1574-automatically-implemented-properties)) can also have an attribute with this target. -- `method` — a constructor; finalizer; method; operator; property get, set, and init accessors; indexer get, set, and init accessors; and event add and remove accessors. A field-like event (i.e., one without accessors) can also have an attribute with this target. +- `method` — a constructor; finalizer; method; operator; property get, set, and init accessors; indexer get, set, and init accessors; event add and remove accessors; and lambda expressions. A field-like event (i.e., one without accessors) can also have an attribute with this target. - `param` — property set and init accessors, indexer set and init accessors, event add and remove accessors, and a parameter in a constructor, method, and operator. - `property` — a property and an indexer. -- `return` — a delegate, method, operator, property get accessor, and indexer get accessor. +- `return` — a delegate, method, operator, property get accessor, indexer get accessor, and lambda expression. - `type` — a delegate, class, struct, enum, and interface. - `typevar` — a type parameter. @@ -285,6 +285,9 @@ Certain contexts permit the specification of an attribute on more than one targe - In the case of an event declaration that does not omit *event_accessor_declarations* the default target is the method. - `method` — the target is the associated method - `param` — the target is the lone parameter +- For an attribute on a *lambda_expression* the default target is the method. Otherwise when the *attribute_target* is equal to: + - `method` — the target is the method + - `return` — the target is the return value In all other contexts, inclusion of an *attribute_target_specifier* is permitted but unnecessary. diff --git a/standard/conversions.md b/standard/conversions.md index d59a034f6..87992ed74 100644 --- a/standard/conversions.md +++ b/standard/conversions.md @@ -63,6 +63,7 @@ The following conversions are classified as implicit conversions: - Implicit tuple conversions ([§10.2.13](conversions.md#10213-implicit-tuple-conversions)) - Default literal conversions ([§10.2.16](conversions.md#10216-default-literal-conversions)) - Implicit throw conversions ([§10.2.17](conversions.md#10217-implicit-throw-conversions)) +- Anonymous function type conversions (§anon-func-type-conversion) Implicit conversions can occur in a variety of situations, including function member invocations ([§12.6.6](expressions.md#1266-function-member-invocation)), cast expressions ([§12.9.8](expressions.md#1298-cast-expressions)), and assignments ([§12.24](expressions.md#1224-assignment-operators)). @@ -376,7 +377,7 @@ A user-defined implicit conversion consists of an optional standard implicit con ### 10.2.15 Anonymous function conversions and method group conversions -Anonymous functions and method groups do not have types in and of themselves, but they may be implicitly converted to delegate types. Additionally, some lambda expressions may be implicitly converted to expression tree types. Anonymous function conversions are described in more detail in [§10.7](conversions.md#107-anonymous-function-conversions) and method group conversions in [§10.8](conversions.md#108-method-group-conversions). +Anonymous functions and method groups do not have types in and of themselves, but they may have a natural type (§anon-func-type). They may be implicitly converted to delegate types. Additionally, some lambda expressions may be implicitly converted to expression tree types. Anonymous function conversions are described in more detail in [§10.7](conversions.md#107-anonymous-function-conversions) and method group conversions in [§10.8](conversions.md#108-method-group-conversions). ### 10.2.16 Default literal conversions @@ -921,6 +922,7 @@ Specifically, an anonymous function `F` is compatible with a delegate type `D` - If `F` does not contain an *anonymous_function_signature*, then `D` may have zero or more parameters of any type, as long as no parameter of `D` is an output parameter. - If `F` has an explicitly typed parameter list, each parameter in `D` has the same modifiers as the corresponding parameter in `F` and an identity conversion exists between the corresponding parameter in `F`. - If `F` has an implicitly typed parameter list, `D` has no reference or output parameters. +- If `F` has an explicit return type, an identity conversion shall exist from the return type of `F` to the return type of `D`. - If the body of `F` is an expression, and *either* `D` has a void return type *or* `F` is async and `D` has a `«TaskType»` return type ([§15.14.1](classes.md#15141-general)), then when each parameter of `F` is given the type of the corresponding parameter in `D`, the body of `F` is a valid expression (w.r.t [§12](expressions.md#12-expressions)) that would be permitted as a *statement_expression* ([§13.7](statements.md#137-expression-statements)). - If the body of `F` is a block, and *either* `D` has a void return type *or* `F` is async and `D` has a `«TaskType»` return type , then when each parameter of `F` is given the type of the corresponding parameter in `D`, the body of `F` is a valid block (w.r.t [§13.3](statements.md#133-blocks)) in which no `return` statement specifies an expression. - If the body of `F` is an expression, and *either* `F` is non-async and `D` has a non-`void` return type `T`, *or* `F` is async and `D` has a `«TaskType»` return type ([§15.14.1](classes.md#15141-general)), then when each parameter of `F` is given the type of the corresponding parameter in `D`, the body of `F` is a valid expression (w.r.t [§12](expressions.md#12-expressions)) that is implicitly convertible to `T`. diff --git a/standard/expressions.md b/standard/expressions.md index 46025c131..d85cca55d 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -910,7 +910,7 @@ An *upper-bound inference from* a type `U` *to* a type `V` is made as follows: An *unfixed* type variable `Xᵢ` with a set of bounds is *fixed* as follows: -- The set of *candidate types* `Uₑ` starts out as the set of all types in the set of bounds for `Xᵢ` where function types are ignored in lower bounds if there are any types that are not function types. +- The set of *candidate types* `Uₑ` starts out as the set of all types in the set of bounds for `Xᵢ` where anonymous function types are ignored in lower bounds if there are any types that are not anonymous function types. - Each bound for `Xᵢ` is examined in turn: For each exact bound U of `Xᵢ` all types `Uₑ` that are not identical to `U` are removed from the candidate set. For each lower bound `U` of `Xᵢ` all types `Uₑ` to which there is *not* an implicit conversion from `U` are removed from the candidate set. For each upper-bound U of `Xᵢ` all types `Uₑ` from which there is *not* an implicit conversion to `U` are removed from the candidate set. - If among the remaining candidate types `Uₑ` there is a unique type `V` to which there is an implicit conversion from all the other candidate types, then `Xᵢ` is fixed to `V`. - Otherwise, type inference fails. @@ -1000,7 +1000,7 @@ The ***inferred return type*** is determined as follows: An *explicit return type inference* is made *from* an expression `E` *to* a type `T` in the following way: -- If `E` is an anonymous function with explicit return type `Uᵣ`, and `T` is a delegate type or expression tree type with return type `Vᵣ`, then an *exact inference* ([§12.6.3.10](expressions.md#126310-exact-inferences) is made *from* `Uᵣ` *to* `Vᵣ`. +- If `E` is an anonymous function with explicit return type `Uᵣ`, and `T` is a delegate type or expression tree type with return type `Vᵣ`, then an *exact inference* ([§12.6.3.10](expressions.md#126310-exact-inferences)) is made *from* `Uᵣ` *to* `Vᵣ`. #### 12.6.3.15 Type inference for conversion of method groups @@ -1027,7 +1027,7 @@ The best common type for a set of expressions `E₁...Eᵥ` is determined as fol - A new *unfixed* type variable `X` is introduced. - For each expression `Ei` an *output type inference* ([§12.6.3.8](expressions.md#12638-output-type-inferences)) is performed from it to `X`. - `X` is *fixed* ([§12.6.3.13](expressions.md#126313-fixing)), if possible, and the resulting type is the best common type. -- Otherwise; inference fails. +- Otherwise, inference fails. > *Note*: Intuitively this inference is equivalent to calling a method `void M(X x₁ ... X xᵥ)` with the `Eᵢ` as arguments and inferring `X`. *end note* @@ -1118,10 +1118,10 @@ Parameter lists for each of the candidate function members are constructed in th 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 a *function_type_conversion*, and +- 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 a *function_type*, and - - for at least one argument, the implicit conversion from `Eᵥ` to `Qᵥ` is a *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 a *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ᵥ`. @@ -5535,6 +5535,8 @@ 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*s may have *attributes* and explicit return types. +The contextual keyword `var` shall not be used as an explicit return type in a *lambda_expression*. + ### 12.22.2 Anonymous function signatures If an *explicit_anonymous_function_parameter_list* or an *implicit_anonymous_function_parameter_list* contains multiple *identifier*s `_`, each of those identifiers denotes a discard ([§9.2.9.2](variables.md#9292-discards)). Otherwise, any single *identifier* `_` denotes a parameter. @@ -5966,7 +5968,7 @@ The delegate type for the anonymous function or method group with parameter type - If `R` is `void`, then the delegate type is `System.Action`; - Otherwise, the delegate type is `System.Func`. -> *Note*: A future eversion of this specification might allow more signatures to bind to `System.Action<>` and `System.Func<>` types (e.g., if `ref struct` types are allowed type arguments).*end note* +> *Note*: A future version of this specification might allow more signatures to bind to `System.Action<>` and `System.Func<>` types (e.g., if `ref struct` types are allowed type arguments). *end note* If two anonymous functions or method groups in the same compilation require synthesized delegate types with the same parameter types and modifiers, and the same return type and modifiers, the compiler shall use the same synthesized delegate type. diff --git a/standard/statements.md b/standard/statements.md index bc26591d2..4d00a55fb 100644 --- a/standard/statements.md +++ b/standard/statements.md @@ -399,7 +399,7 @@ An *implicitly_typed_local_variable_declaration* introduces a single local varia > var x; // Error, no initializer to infer type from > var y = {1, 2, 3}; // Error, array initializer not permitted > var z = null; // Error, null does not have a type -> var u = x => x + 1; // Error, anonymous functions do not have a type +> var u = x => x + 1; // Error, no natural type > var v = v++; // Error, initializer cannot refer to v itself > ``` >