Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
6a73647
Add support for native-sized integers
RexJaeschke Mar 17, 2024
ebe614d
missing back tick
BillWagner Nov 7, 2025
563f374
Add entry for nint/nuint
RexJaeschke Nov 9, 2025
9d19d32
Apply suggestions from code review
RexJaeschke Nov 16, 2025
3e10994
Apply suggestions from code review
RexJaeschke Nov 16, 2025
1bfce0b
address open comments.
BillWagner Jan 9, 2026
1b49905
Address current comments.
BillWagner Jan 9, 2026
49797ad
Edit pass on `nint`
BillWagner Jan 12, 2026
56cc6f8
Apply suggestions from code review
BillWagner Jan 29, 2026
4e64371
respond to first round feedback.
BillWagner Jan 29, 2026
1bcaf04
Rework Types.md for nint
BillWagner Feb 2, 2026
4d9ae4a
Add predefined operators
BillWagner Feb 2, 2026
7d80804
Further edits.
BillWagner Feb 2, 2026
74f0613
one more edit
BillWagner Feb 2, 2026
b647425
Apply suggestions from code review
BillWagner Feb 26, 2026
afe0a7c
Update standard/conversions.md
BillWagner Feb 26, 2026
e4352ce
lint
BillWagner Feb 26, 2026
cfb9cac
Apply suggestions from code review
BillWagner Feb 26, 2026
004ded7
Apply suggestion from @Nigel-Ecma
BillWagner Feb 26, 2026
b14f438
remove extra note.
BillWagner Feb 26, 2026
a517663
Address operator feedback
BillWagner Feb 27, 2026
755c835
Add additional promotions
BillWagner Feb 27, 2026
586d0d1
Constant expression fix
BillWagner Feb 27, 2026
53705cb
misc formatting fixes
BillWagner Feb 27, 2026
fd15588
remove redundant conversions
BillWagner Feb 27, 2026
d7f8c8a
em-dashes to hyphen-minus
BillWagner Feb 27, 2026
58b7404
Update RightShift stderr reference for nint/nuint keywords
BillWagner Apr 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion standard/arrays.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
A *non_array_type* is any *type* that is not itself an *array_type*.

When determining the rank and element type of array type as specified below, only the *rank_specifier*s in the outer-most production are considered, so in the production `array_type nullable_type_annotation rank_specifier+`, any `rank_specifier` within the `array_type` is ignored.

Check warning on line 39 in standard/arrays.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/arrays.md#L39

MDC032::Line length 83 > maximum 81
The rank of an array type is given by the leftmost *rank_specifier* in the *array_type*: A *rank_specifier* indicates that the array is an array with a rank of one plus the number of “`,`” tokens in the *rank_specifier*.

The element type of an array type is the type that results from deleting the leftmost *rank_specifier* from the *array_type*.
Expand Down Expand Up @@ -154,7 +154,7 @@

## 17.4 Array element access

Array elements are accessed using the *array access* variant of *element_access* expressions ([§12.8.12.2](expressions.md#128122-array-access)) of the form `A[I₁, I₂, ..., Iₓ]`, where `A` is an expression of an array type and each `Iₑ` is an expression of type `int`, `uint`, `long`, `ulong`, or can be implicitly converted to one or more of these types. The result of an array access is a variable reference ([§9.5](variables.md#95-variable-references)) to the array element selected by the indices.
Array elements are accessed using the *array access* variant of *element_access* expressions ([§12.8.12.2](expressions.md#128122-array-access)) of the form `A[I₁, I₂, ..., Iₓ]`, where `A` is an expression of an array type and each `Iₑ` is an expression of type `int`, `uint`, `nint`, `nuint`, `long`, `ulong`, or can be implicitly converted to one or more of these types. The result of an array access is a variable reference ([§9.5](variables.md#95-variable-references)) to the array element selected by the indices.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What was the reason to have listed int and uint in the first place? They fall under "can be implicitly converted to long/ulong."

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Completeness for one. And, to make it clear that in those cases, no conversion is required.


Array elements of single-dimensional arrays can also be accessed using an array access expression where the sole index, `I₁`, is an expression of type `Index`, `Range`, or can be implicitly converted to one or both of these types. If `I₁` is of type `Index`, or has been implicitly converted to that type, then the result of the array access is a variable reference to the array element selected by the index value. If `I₁` is of type `Range`, or has been implicitly converted to that type, then the result of the array access is a new array formed from a shallow copy of the array elements with indices in the `Range`, maintaining the element order.

Expand Down
4 changes: 2 additions & 2 deletions standard/classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,28 @@
## 15.1 General

A class is a data structure that may contain data members (constants and fields), function members (methods, properties, events, indexers, operators, instance constructors, finalizers, and static constructors), and nested types. Class types support inheritance, a mechanism whereby a ***derived class*** can extend and specialize a ***base class***.

Check warning on line 6 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L6

MDC032::Line length 83 > maximum 81
Structs ([§16](structs.md#16-structs)) and interfaces ([§19](interfaces.md#19-interfaces)) have members similar to classes but with certain restrictions. This clause defines the declarations for classes and class members. The clauses for structs and interfaces define the restrictions for those types in terms of the corresponding declarations in class types.

## 15.2 Class declarations

Check warning on line 10 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L10

MDC032::Line length 83 > maximum 81
### 15.2.1 General

Check warning on line 12 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L12

MDC032::Line length 87 > maximum 81
A *class_declaration* is a *type_declaration* ([§14.7](namespaces.md#147-type-declarations)) that declares a new class.

```ANTLR
class_declaration

Check warning on line 16 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L16

MDC032::Line length 86 > maximum 81
: attributes? class_modifier* 'partial'? 'class' identifier
type_parameter_list? class_base? type_parameter_constraints_clause*

Check warning on line 18 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L18

MDC032::Line length 84 > maximum 81
class_body ';'?
;

Check warning on line 20 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L20

MDC032::Line length 82 > maximum 81
```

A *class_declaration* consists of an optional set of *attributes* ([§23](attributes.md#23-attributes)), followed by an optional set of *class_modifier*s ([§15.2.2](classes.md#1522-class-modifiers)), followed by an optional `partial` modifier ([§15.2.7](classes.md#1527-partial-type-declarations)), followed by the keyword `class` and an *identifier* that names the class, followed by an optional *type_parameter_list* ([§15.2.3](classes.md#1523-type-parameters)), followed by an optional *class_base* specification ([§15.2.4](classes.md#1524-class-base-specification)), followed by an optional set of *type_parameter_constraints_clause*s ([§15.2.5](classes.md#1525-type-parameter-constraints)), followed by a *class_body* ([§15.2.6](classes.md#1526-class-body)), optionally followed by a semicolon.

A class declaration shall not supply *type_parameter_constraints_clause*s unless it also supplies a *type_parameter_list*.

A class declaration that supplies a *type_parameter_list* is a generic class declaration. Additionally, any class nested inside a generic class declaration or a generic struct declaration is itself a generic class declaration, since type arguments for the containing type shall be supplied to create a constructed type ([§8.4](types.md#84-constructed-types)).

Check warning on line 27 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L27

MDC032::Line length 82 > maximum 81

### 15.2.2 Class modifiers

Expand Down Expand Up @@ -1556,7 +1556,7 @@

The *type* of a *constant_declaration* specifies the type of the members introduced by the declaration. The type is followed by a list of *constant_declarator*s ([§13.6.3](statements.md#1363-local-constant-declarations)), each of which introduces a new member. A *constant_declarator* consists of an *identifier* that names the member, followed by an “`=`” token, followed by a *constant_expression* ([§12.25](expressions.md#1225-constant-expressions)) that gives the value of the member.

The *type* specified in a constant declaration shall be `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `char`, `float`, `double`, `decimal`, `bool`, `string`, an *enum_type*, or a *reference_type*. Each *constant_expression* shall yield a value of the target type or of a type that can be converted to the target type by an implicit conversion ([§10.2](conversions.md#102-implicit-conversions)).
The *type* specified in a constant declaration shall be `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `nint`, `nuint`, `long`, `ulong`, `char`, `float`, `double`, `decimal`, `bool`, `string`, an *enum_type*, or a *reference_type*. Each *constant_expression* shall yield a value of the target type or of a type that can be converted to the target type by an implicit conversion ([§10.2](conversions.md#102-implicit-conversions)).

The *type* of a constant shall be at least as accessible as the constant itself ([§7.5.5](basic-concepts.md#755-accessibility-constraints)).

Expand Down Expand Up @@ -1790,7 +1790,7 @@

- A *reference_type*.
- A *type_parameter* that is known to be a reference type ([§15.2.5](classes.md#1525-type-parameter-constraints)).
- The type `byte`, `sbyte`, `short`, `ushort`, `int`, `uint`, `char`, `float`, `bool`, `System.IntPtr`, or `System.UIntPtr`.
- The type `byte`, `sbyte`, `short`, `ushort`, `int`, `uint`, `nint`, `nuint`, `char`, `float`, `bool`, `System.IntPtr`, or `System.UIntPtr`.
- An *enum_type* having an *enum_base* type of `byte`, `sbyte`, `short`, `ushort`, `int`, or `uint`.

> *Example*: The example
Expand Down
51 changes: 31 additions & 20 deletions standard/conversions.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
> ```csharp
> enum Color { Red, Blue, Green }
>
> // The expression 0 converts implicitly to enum types

Check warning on line 28 in standard/conversions.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/conversions.md#L28

MDC032::Line length 82 > maximum 81
> Color c0 = 0;
>
> // Other int expressions need explicit conversion
Expand Down Expand Up @@ -83,6 +83,7 @@
- Between `object` and `dynamic`.
- Between all tuple types with the same arity, and the corresponding constructed `ValueTuple<...>` type, when an identity conversion exists between each pair of corresponding element types.
- Between types constructed from the same generic type where there exists an identity conversion between each corresponding type argument.
- Between array types containing elements of type `T` and `S`, such as `T[]` and `S[]`, where the rank of the two arrays is the same and there is an identity conversion between `T` and `S`.

> *Example*: The following illustrates the recursive nature of the third rule:
>
Expand Down Expand Up @@ -115,22 +116,26 @@

In most cases, an identity conversion has no effect at runtime. However, since floating point operations may be performed at higher precision than prescribed by their type ([§8.3.7](types.md#837-floating-point-types)), assignment of their results may result in a loss of precision, and explicit casts are guaranteed to reduce precision to what is prescribed by the type ([§12.9.8](expressions.md#1298-cast-expressions)).

There is an identity conversion between `nint` and `System.IntPtr`, and between `nuint` and `System.UIntPtr`.

### 10.2.3 Implicit numeric conversions

The implicit numeric conversions are:

- From `sbyte` to `short`, `int`, `long`, `float`, `double`, or `decimal`.
- From `byte` to `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `float`, `double`, or `decimal`.
- From `short` to `int`, `long`, `float`, `double`, or `decimal`.
- From `ushort` to `int`, `uint`, `long`, `ulong`, `float`, `double`, or `decimal`.
- From `int` to `long`, `float`, `double`, or `decimal`.
- From `uint` to `long`, `ulong`, `float`, `double`, or `decimal`.
- From `sbyte` to `short`, `int`, `nint`, `long`, `float`, `double`, or `decimal`.
- From `byte` to `short`, `ushort`, `int`, `uint`, `nint`, `nuint`, `long`, `ulong`, `float`, `double`, or `decimal`.
- From `short` to `int`, `nint`, `long`, `float`, `double`, or `decimal`.
- From `ushort` to `int`, `uint`, `nint`, `nuint`, `long`, `ulong`, `float`, `double`, or `decimal`.
- From `int` to `nint`, `long`, `float`, `double`, or `decimal`.
- From `uint` to `nuint`, `long`, `ulong`, `float`, `double`, or `decimal`.
- From `nint` to `long`, `float`, `double`, or `decimal`.
- From `nuint` to `ulong`, `float`, `double`, or `decimal`.
- From `long` to `float`, `double`, or `decimal`.
- From `ulong` to `float`, `double`, or `decimal`.
- From `char` to `ushort`, `int`, `uint`, `long`, `ulong`, `float`, `double`, or `decimal`.
- From `char` to `ushort`, `int`, `uint`, `nint`, `nuint`, `long`, `ulong`, `float`, `double`, or `decimal`.
- From `float` to `double`.

Conversions from `int`, `uint`, `long` or `ulong` to `float` and from `long` or `ulong` to `double` may cause a loss of precision, but will never cause a loss of magnitude. The other implicit numeric conversions never lose any information.
Conversions from `int`, `uint`, `nint`, `nuint`, `long` or `ulong` to `float` and from `nint`, `nuint`, `long` or `ulong` to `double` may cause a loss of precision, but will never cause a loss of magnitude. The other implicit numeric conversions never lose any information.

There are no predefined implicit conversions to the `char` type, so values of the other integral types do not automatically convert to the `char` type.

Expand Down Expand Up @@ -315,9 +320,13 @@

An implicit constant expression conversion permits the following conversions:

- A *constant_expression* ([§12.25](expressions.md#1225-constant-expressions)) of type `int` can be converted to type `sbyte`, `byte`, `short`, `ushort`, `uint`, or `ulong`, provided the value of the *constant_expression* is within the range of the destination type.
- A *constant_expression* ([§12.25](expressions.md#1225-constant-expressions)) of type `int` can be converted to type `sbyte`, `byte`, `short`, `ushort`, `uint`, `nuint`, or `ulong`, provided the value of the *constant_expression* is within the range of the destination type.
- A *constant_expression* of type `long` can be converted to type `ulong`, provided the value of the *constant_expression* is not negative.

The range for constants of type `nint` is the same range as `int`, and the range for constants of type `nuint` is the same range as `uint` ([§12.25](expressions.md#1225-constant-expressions)).

> *Note*: This is a consequence of `nint`/`nuint` being the same size as, or larger than, `int`/`uint` ([§8.3.6](types.md#836-integral-types)). *end note*

### 10.2.12 Implicit conversions involving type parameters

For a *type_parameter* `T` that is known to be a reference type ([§15.2.5](classes.md#1525-type-parameter-constraints)), the following implicit reference conversions ([§10.2.8](conversions.md#1028-implicit-reference-conversions)) exist:
Expand Down Expand Up @@ -419,18 +428,20 @@

The explicit numeric conversions are the conversions from a *numeric_type* to another *numeric_type* for which an implicit numeric conversion ([§10.2.3](conversions.md#1023-implicit-numeric-conversions)) does not already exist:

- From `sbyte` to `byte`, `ushort`, `uint`, `ulong`, or `char`.
- From `sbyte` to `byte`, `ushort`, `uint`, `ulong`, `nuint`, or `char`.
- From `byte` to `sbyte` or `char`.
- From `short` to `sbyte`, `byte`, `ushort`, `uint`, `ulong`, or `char`.
- From `short` to `sbyte`, `byte`, `ushort`, `uint`, `nuint`, `ulong`, or `char`.
- From `ushort` to `sbyte`, `byte`, `short`, or `char`.
- From `int` to `sbyte`, `byte`, `short`, `ushort`, `uint`, `ulong`, or `char`.
- From `uint` to `sbyte`, `byte`, `short`, `ushort`, `int`, or `char`.
- From `long` to `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `ulong`, or `char`.
- From `ulong` to `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, or `char`.
- From `int` to `sbyte`, `byte`, `short`, `ushort`, `uint`, `nuint`, `ulong`, or `char`.
- From `uint` to `sbyte`, `byte`, `short`, `ushort`, `int`, `nint`, or `char`.
- From `nint` to `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `nuint`, `ulong`, or `char`.
- From `nuint` to `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `nint`, `long`, or `char`.
- From `long` to `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `nint`, `nuint`, `ulong`, or `char`.
- From `ulong` to `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `nint`, `nuint`, `long`, or `char`.
- From `char` to `sbyte`, `byte`, or `short`.
- From `float` to `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `char`, or `decimal`.
- From `double` to `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `char`, `float`, or `decimal`.
- From `decimal` to `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `char`, `float`, or `double`.
- From `float` to `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `nint`, `nuint`, `long`, `ulong`, `char`, or `decimal`.
- From `double` to `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `nint`, `nuint`, `long`, `ulong`, `char`, `float`, or `decimal`.
- From `decimal` to `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `nint`, `nuint`, `long`, `ulong`, `char`, `float`, or `double`.

Because the explicit conversions include all implicit and explicit numeric conversions, it is always possible to convert from any *numeric_type* to any other *numeric_type* using a cast expression ([§12.9.8](expressions.md#1298-cast-expressions)).

Expand Down Expand Up @@ -464,8 +475,8 @@

The explicit enumeration conversions are:

- From `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `char`, `float`, `double`, or `decimal` to any *enum_type*.
- From any *enum_type* to `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `char`, `float`, `double`, or `decimal`.
- From `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `nint`, `nuint`, `long`, `ulong`, `char`, `float`, `double`, or `decimal` to any *enum_type*.
- From any *enum_type* to `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `nint`, `nuint`, `long`, `ulong`, `char`, `float`, `double`, or `decimal`.
- From any *enum_type* to any other *enum_type*.

An explicit enumeration conversion between two types is processed by treating any participating *enum_type* as the underlying type of that *enum_type*, and then performing an implicit or explicit numeric conversion between the resulting types.
Expand Down
4 changes: 1 addition & 3 deletions standard/enums.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,7 @@ enum_body
;
```

Each enum type has a corresponding integral type called the ***underlying type*** of the enum type. This underlying type shall be able to represent all the enumerator values defined in the enumeration. If the *enum_base* is present, it explicitly declares the underlying type. The underlying type shall be one of the *integral types* ([§8.3.6](types.md#836-integral-types)) other than `char`. The underlying type may be specified either by an `integral_type` ([§8.3.5](types.md#835-simple-types)), or an `integral_type_name`. The `integral_type_name` is resolved in the same way as `type_name` ([§7.8.1](basic-concepts.md#781-general)), including taking any using directives ([§14.5](namespaces.md#145-using-directives)) into account.

> *Note*: The `char` type cannot be used as an underlying type, either by keyword or via an `integral_type_name`. *end note*
Each enum type has a corresponding integral type called the ***underlying type*** of the enum type. This underlying type shall be able to represent all the enumerator values defined in the enumeration. If the *enum_base* is present, it explicitly declares the underlying type. The underlying type shall be one of the *integral types* ([§8.3.6](types.md#836-integral-types)) other than `nint`, `nuint`, and `char`. The underlying type may be specified either by an `integral_type` ([§8.3.5](types.md#835-simple-types)), or an `integral_type_name`. The `integral_type_name` is resolved in the same way as `type_name` ([§7.8.1](basic-concepts.md#781-general)), including taking any using directives ([§14.5](namespaces.md#145-using-directives)) into account.

An enum declaration that does not explicitly declare an underlying type has an underlying type of `int`.

Expand Down
Loading
Loading