diff --git a/standard/classes.md b/standard/classes.md index 594d56fb5..4c4792f58 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -1531,14 +1531,14 @@ The following method names are reserved. While many have corresponding operators | `op_BitwiseAndAssignment` | (reserved) | | `op_BitwiseOr` | `\|` | | `op_BitwiseOrAssignment` | (reserved) | -| `op_CheckedAddition` | (reserved for future use) | -| `op_CheckedDecrement` | (reserved for future use) | -| `op_CheckedDivision` | (reserved for future use) | -| `op_CheckedExplicit` | (reserved for future use) | -| `op_CheckedIncrement` | (reserved for future use) | -| `op_CheckedMultiply` | (reserved for future use) | -| `op_CheckedSubtraction` | (reserved for future use) | -| `op_CheckedUnaryNegation` | (reserved for future use) | +| `op_CheckedAddition` | checked addition `+` | +| `op_CheckedDecrement` | checked decrement `--` | +| `op_CheckedDivision` | checked division `/` | +| `op_CheckedExplicit` | checked explicit (narrowing) coercion | +| `op_CheckedIncrement` | checked increment `++` | +| `op_CheckedMultiply` | checked multiply `*` | +| `op_CheckedSubtraction` | checked subtraction `-` | +| `op_CheckedUnaryNegation` | checked unary negation `-` | | `op_Comma` | (reserved) | | `op_Decrement` | `--` (prefix and postfix) | | `op_Division` | `/` | @@ -4920,7 +4920,7 @@ logical_negation_operator ; overloadable_unary_operator - : '+' | '-' | logical_negation_operator | '~' | '++' | '--' | 'true' | 'false' + : '+' | 'checked'? '-' | '!' | '~' | 'checked'? '++' | 'checked'? '--' | 'true' | 'false' ; binary_operator_declarator @@ -4929,13 +4929,13 @@ binary_operator_declarator ; overloadable_binary_operator - : '+' | '-' | '*' | '/' | '%' | '&' | '|' | '^' | '<<' - | right_shift | '==' | '!=' | '>' | '<' | '>=' | '<=' + : 'checked'? '+' | 'checked'? '-' | 'checked'? '*' | 'checked'? '/' | '%' | '&' | '|' | '^' | '<<' + | right_shift | '==' | '!=' | '>' | '<' | '>=' | '<=' ; conversion_operator_declarator : 'implicit' 'operator' type '(' fixed_parameter ')' - | 'explicit' 'operator' type '(' fixed_parameter ')' + | 'explicit' 'operator' 'checked'? type '(' fixed_parameter ')' ; operator_body @@ -4971,6 +4971,17 @@ Additional information on unary and binary operators can be found in [§12.4](e Additional information on conversion operators can be found in [§10.5](conversions.md#105-user-defined-conversions). +An *operator_declaration* containing `checked` declares a ***checked operator***. For each checked operator in that type there shall be a corresponding ***regular operator*** having the same signature, but without `checked`, and return type. + +> *Note*: The opposite is not required. Specifically, an *operator_declaration* without `checked` need not have a matching checked operator. When this is the case, the operator is neither a checked operator nor a regular operator. *end note* + +It is suggested that a user-defined checked operator throw an exception (such as `System.OverflowException`) when the result of an operation is too large to represent in the destination type, whatever that might mean for that type. + +It is suggested that a user-defined regular operator not throw an exception when the result of an operation is too large to represent in the destination type, whatever that might mean for that type. Instead, it should return an instance representing a truncated result, whatever that might mean for that type. + +A checked operator does not implement a regular operator, and vice versa. +The presence of `checked` in a checked operator declaration has no effect on the checked context of that operator’s *operator_body*. That is controlled by the `checked` and `unchecked` operators or statements present in that *operator_body*, or by the default checking context provided by the runtime environment. + ### 15.10.2 Unary operators The following rules apply to unary operator declarations, where `T` denotes the instance type of the class or struct that contains the operator declaration: @@ -5135,7 +5146,7 @@ For all types but `object`, the operators declared by the `Convertible` type User-defined conversions are not allowed to convert from or to *interface_type*s. In particular, this restriction ensures that no user-defined transformations occur when converting to an *interface_type*, and that a conversion to an *interface_type* succeeds only if the `object` being converted actually implements the specified *interface_type*. -The signature of a conversion operator consists of the source type and the target type. (This is the only form of member for which the return type participates in the signature.) The implicit or explicit classification of a conversion operator is not part of the operator’s signature. Thus, a class or struct cannot declare both an implicit and an explicit conversion operator with the same source and target types. +The signature of a conversion operator consists of the source type and the target type. (This is the only form of member for which the return type participates in the signature.) To allow a type to have both checked and regular operators with the same source- and target-type combination, the signature of a checked conversion operator also includes the fact that it is checked. The implicit or explicit classification of a conversion operator is not part of the operator’s signature. Thus, a class or struct cannot declare both an implicit and an explicit conversion operator with the same source and target types. > *Note*: In general, user-defined implicit conversions should be designed to never throw exceptions and never lose information. If a user-defined conversion can give rise to exceptions (for example, because the source argument is out of range) or loss of information (such as discarding high-order bits), then that conversion should be defined as an explicit conversion. *end note* diff --git a/standard/conversions.md b/standard/conversions.md index 39acaacc0..674b4f335 100644 --- a/standard/conversions.md +++ b/standard/conversions.md @@ -770,6 +770,9 @@ A user-defined explicit conversion from an expression `E` to a type `T` is pro - If `S` or `T` are nullable value types, let `Sᵢ` and `Tᵢ` be their underlying types, otherwise let `Sᵢ` and `Tᵢ` be `S` and `T`, respectively. - If `Sᵢ` or `Tᵢ` are type parameters, let `S₀` and `T₀` be their effective base classes, otherwise let `S₀` and `T₀` be `Sᵢ` and `Tᵢ`, respectively. - Find the set of types, `D`, from which user-defined conversion operators will be considered. This set consists of `S₀` (if `S₀` exists and is a class or struct), the base classes of `S₀` (if `S₀` exists and is a class), `T₀` (if `T₀` is a class or struct), and the base classes of `T₀` (if `T₀` is a class). A type is added to the set `D` only if an identity conversion to another type already included in the set doesn’t exist. +- Find the set of conversion operators, `U₀`. This set consists of: + - In an `unchecked` evaluation context, the user-defined implicit or regular explicit conversion operators declared by the classes or structs in `D`. + - In a `checked` evaluation context, the user-defined implicit or regular/checked explicit conversion operators declared by the classes or structs in `D` except for regular explicit conversion operators that have a pair-wise matching checked operator declaration within the same declaring type. - Find the set of applicable user-defined and lifted conversion operators, `U`. This set consists of the user-defined and lifted implicit or explicit conversion operators declared by the classes or structs in `D` that convert from a type encompassing `E` or encompassed by `S` (if it exists) to a type encompassing or encompassed by `T`. If `U` is empty, the conversion is undefined and a compile-time error occurs. - Find the most-specific source type, `Sₓ`, of the operators in `U`: - If `S` exists and any of the operators in `U` convert from `S`, then `Sₓ` is `S`. @@ -1058,6 +1061,10 @@ Not every lambda expression can be converted to expression tree types. The conve > > *end note* +The addition of support for checked operators resulted in the addition of the following factory methods to `System.Linq.Expressions.Expression`: `NegateChecked`, `AddChecked`, `SubtractChecked`, `MultiplyChecked`, and `ConvertChecked`. (There is no factory method for checked division.) + +> *Note*: As assignment is not supported in an expression tree, there are no such factory methods for checked increment or checked decrement. *end note* + ## 10.8 Method group conversions An implicit conversion exists from a method group ([§12.2](expressions.md#122-expression-classifications)) to a compatible delegate type ([§21.4](delegates.md#214-delegate-compatibility)). If `D` is a delegate type, and `E` is an expression that is classified as a method group, then `D` is compatible with `E` if and only if `E` contains at least one method that is applicable in its normal form ([§12.6.4.2](expressions.md#12642-applicable-function-member)) to any argument list ([§12.6.2](expressions.md#1262-argument-lists)) having types and modifiers matching the parameter types and modifiers of `D`, as described in the following. diff --git a/standard/documentation-comments.md b/standard/documentation-comments.md index a6dbfbde9..f08b75313 100644 --- a/standard/documentation-comments.md +++ b/standard/documentation-comments.md @@ -963,7 +963,7 @@ IDs: "M:Acme.Widget.op_UnaryPlus(Acme.Widget)" ``` -The complete set of unary operator function names used is as follows: `op_UnaryPlus`, `op_UnaryNegation`, `op_LogicalNot`, `op_OnesComplement`, `op_Increment`, `op_Decrement`, `op_True`, and `op_False`. +The complete set of unary operator function names used is as follows: `op_UnaryPlus`, `op_UnaryNegation`, `op_CheckedUnaryNegation`, `op_LogicalNot`, `op_OnesComplement`, `op_Increment`, `op_CheckedIncrement`, `op_Decrement`, `op_CheckedDecrement`, `op_True`, and `op_False`. **Binary operators** @@ -984,10 +984,12 @@ IDs: "M:Acme.Widget.op_Addition(Acme.Widget,Acme.Widget)" ``` -The complete set of binary operator function names used is as follows: `op_Addition`, `op_Subtraction`, `op_Multiply`, `op_Division`, `op_Modulus`, `op_BitwiseAnd`, `op_BitwiseOr`, `op_ExclusiveOr`, `op_LeftShift`, `op_RightShift`, `op_Equality`, `op_Inequality`, `op_LessThan`, `op_LessThanOrEqual`, `op_GreaterThan`, and `op_GreaterThanOrEqual`. +The complete set of binary operator function names used is as follows: `op_Addition`, `op_CheckedAddition`, `op_Subtraction`, `op_CheckedSubtraction`, `op_Multiply`, `op_CheckedMultiply`, `op_Division`, `op_CheckedDivision`, `op_Modulus`, `op_BitwiseAnd`, `op_BitwiseOr`, `op_ExclusiveOr`, `op_LeftShift`, `op_RightShift`, `op_Equality`, `op_Inequality`, `op_LessThan`, `op_LessThanOrEqual`, `op_GreaterThan`, and `op_GreaterThanOrEqual`. **Conversion operators** have a trailing “`~`” followed by the return type. When either the source or destination of a conversion operator is a generic type, the “`<`” and “`">`” characters are replaced by the “`{`” and “`}`” characters, respectively. +The complete set of conversion operator function names used is as follows: `op_Explicit`, `op_CheckedExplicit`, and `op_Implicit`. + ```csharp namespace Acme diff --git a/standard/expressions.md b/standard/expressions.md index 82ce81a03..b99f79165 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -264,6 +264,9 @@ An operation of the form `x «op» y`, where «op» is an overloadable binary Given a type `T` and an operation `operator «op»(A)`, where «op» is an overloadable operator and `A` is an argument list, the set of candidate user-defined operators provided by `T` for operator `«op»(A)` is determined as follows: - Determine the type `T₀`. If `T` is a nullable value type, `T₀` is its underlying type; otherwise, `T₀` is equal to `T`. +- Find the set of user-defined operators, `U`. This set consists of: + - In an `unchecked` evaluation context, all regular `operator «op»` declarations in `T₀`. + - In a `checked` evaluation context, all checked and non-checked `operator «op»` declarations in `T₀` except regular declarations that have a pair-wise matching checked operator declaration. - For all `operator «op»` declarations in `T₀` and all lifted forms of such operators, if at least one operator is applicable ([§12.6.4.2](expressions.md#12642-applicable-function-member)) with respect to the argument list `A`, then the set of candidate operators consists of all such applicable operators in `T₀`. - Otherwise, if `T₀` is `object`, the set of candidate operators is empty. - Otherwise, the set of candidate operators provided by `T₀` is the set of candidate operators provided by the direct base class of `T₀`, or the effective base class of `T₀` if `T₀` is a type parameter. @@ -3375,7 +3378,7 @@ For an enum type `T`, the result of the expression `sizeof(T)` is a constant va ### 12.8.20 The checked and unchecked operators -The `checked` and `unchecked` operators are used to control the overflow-checking context for integral-type arithmetic operations and conversions. +The `checked` and `unchecked` operators are used to control the overflow-checking context for integral-type arithmetic operations and conversions. They may also be used to control the overflow-checking context for various operations and conversions involving user-defined types ([§15.10.1](classes.md#15101-general) and [§15.10.4](classes.md#15104-conversion-operators)). ```ANTLR checked_expression diff --git a/standard/standard-library.md b/standard/standard-library.md index 153bffed1..bb6beb360 100644 --- a/standard/standard-library.md +++ b/standard/standard-library.md @@ -779,6 +779,16 @@ namespace System.Linq.Expressions public sealed class Expression { public TDelegate Compile(); + public static UnaryExpression NegateChecked(Expression expression, + MethodInfo? method); + public static BinaryExpression AddChecked(Expression left, + Expression right, MethodInfo? method); + public static BinaryExpression SubtractChecked(Expression left, + Expression right, MethodInfo? method); + public static BinaryExpression MultiplyChecked(Expression left, + Expression right, MethodInfo? method); + public static UnaryExpression ConvertChecked(Expression expression, + Type type, MethodInfo? method); } } diff --git a/standard/statements.md b/standard/statements.md index b10990ce7..762d07da6 100644 --- a/standard/statements.md +++ b/standard/statements.md @@ -1893,7 +1893,7 @@ The end point of a `try` statement is reachable if both of the following are tru ## 13.12 The checked and unchecked statements -The `checked` and `unchecked` statements are used to control the ***overflow-checking context*** for integral-type arithmetic operations and conversions. +The `checked` and `unchecked` statements are used to control the ***overflow-checking context*** for integral-type arithmetic operations and conversions. They may also be used to control the overflow-checking context for various operations and conversions involving user-defined types ([§15.10.1](classes.md#15101-general) and [§15.10.4](classes.md#15104-conversion-operators)). ```ANTLR checked_statement