Skip to content

[Version 9.0] Feature support for native sized integers (nint, and nuint)#1457

Draft
BillWagner wants to merge 26 commits intodraft-v9from
v9-native-sized-integers
Draft

[Version 9.0] Feature support for native sized integers (nint, and nuint)#1457
BillWagner wants to merge 26 commits intodraft-v9from
v9-native-sized-integers

Conversation

@BillWagner
Copy link
Member

@BillWagner BillWagner commented Nov 7, 2025

I wrote the bulk of this spec some years ago (based on the V9 MS proposal), and was happy with it. Then several years later, when I started looking at V11 features, I discovered that this topic was revisited (see V11 MS proposal). And I got confused as to which things should go in the V9 standard and which in the V11. Hopefully, I have it right now as far as V9 goes, but anyone reviewing this PR would do well to at least be conversant with how things will be changed in V11, to make sure the V9 spec is complete/correct. [Outside GitHub I have a Word document showing the expected changes for V11; ping me to get a copy (which Bill and Mads also have).] Rex

The commits from #1060 were squashed into one commit in this PR.

There are several comments on #1060 that need to be addressed:

@BillWagner BillWagner changed the title Feature support for native sized integers (nint, and nuint) [Version 9.0] Feature support for native sized integers (nint, and nuint) Nov 7, 2025
@RexJaeschke RexJaeschke added this to the C# 9.0 milestone Nov 9, 2025
@RexJaeschke
Copy link
Contributor

Can someone please check if changes should be made to §12.6.4.7.

@RexJaeschke RexJaeschke added the type: feature This issue describes a new feature label Nov 12, 2025
@RexJaeschke RexJaeschke added the Review: pending Proposal is available for review label Nov 16, 2025
@BillWagner BillWagner self-assigned this Dec 2, 2025
@jnm2 jnm2 mentioned this pull request Dec 16, 2025
@BillWagner BillWagner force-pushed the v9-native-sized-integers branch from eda247c to 746fdf2 Compare January 9, 2026 19:46
@BillWagner BillWagner added the meeting: discuss This issue should be discussed at the next TC49-TG2 meeting label Jan 12, 2026
@BillWagner
Copy link
Member Author

BillWagner commented Jan 12, 2026

Retaining draft status for this meeting.

If there's time, I'd like to have everyone get a first look at this before the January meeting.

There's an interesting time discussion: The changes to the feature will remove quite a bit of language from the standard. Once the keywords nint and nuint are synonyms for System.IntPtr and System.UIntPtr, the text for overloading, overriding and hiding goes away. The implicit conversions also go away. The built-in operator discussion changes: the built-in operators become the members of those System types.

Do we want full fidelity in both versions? If not, how much hand-waving for temporary C# 9 behavior do we allow?

>
> *end note*.

Although `nint` and `nuint` shall be represented by the types `System.IntPtr` and `System.UIntPtr`, respectively, `nint` and `nuint` are *not* aliases for those types. As such, not all members of the corresponding `System` types are defined for `nint` and `nuint`. Instead, the compiler shall make available additional conversions, unary operators (§12.9) and arithmetic operators (§12.12) for the types `System.IntPtr` and `System.UIntPtr` when used in the context of native integer types.
Copy link
Contributor

Choose a reason for hiding this comment

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

We've said that there's an identity conversion between nint and IntPtr - but do we say elsewhere that IntPtr must be used to represent nint values? It may well be somewhere, and I've missed it...

Copy link
Contributor

Choose a reason for hiding this comment

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

(Line 365 of this file states it, effectively - but given that that is after this paragraph, presumably it's somewhere else as well...)

Copy link
Contributor

Choose a reason for hiding this comment

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

(Not sure what "shall be represented" even means in the language spec...)

Copy link
Contributor

Choose a reason for hiding this comment

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

I think we might be able to remove a lot of the distinction, but more work required for us to be sure. What I think we might be seeing here are two different things:

  1. The language adding contextual keywords in C#9, and moving to keywords in C#11
  2. An implementation changing how it provides the language features in its C#11 release compared to how it provided them in its C#9 & C#10 releases.

If this is correct then (1) is for the Standard and (2) is not.

Copy link
Member Author

Choose a reason for hiding this comment

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

That implementation change likely has impact on the standard.

Until there was runtime support for checked and unchecked user defined operators, System.IntPtr and System.UIntPtr couldn't support the correct behavior for numeric types. We need to discuss how we want to handle that requirement.

public void* ToPointer();
```

The remaining members of `System.IntPtr` and `System.UIntPtr` are implicitly included in `nint` and `nuint`. These are:
Copy link
Contributor

Choose a reason for hiding this comment

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

"These are" sounds like we're prohibiting the introduction of other members, which we've previously said would be okay for an implementation to do. Let's discuss what we want to require here.

Copy link
Member Author

Choose a reason for hiding this comment

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

I removed the list. I think it's valid just to say "everything else"

@jskeet
Copy link
Contributor

jskeet commented Jan 14, 2026

Next step: @BillWagner to see whether it would be possible to spec this in a way that looks forward to C# 11 more, defining them as aliases but specifying the exceptions in one place (e.g. no bitwise shift on IntPtr), and then removing that section for C# 11.

@jnm2
Copy link
Contributor

jnm2 commented Jan 15, 2026

There's an interesting time discussion: The changes to the feature will remove quite a bit of language from the standard. Once the keywords nint and nuint are synonyms for System.IntPtr and System.UIntPtr, the text for overloading, overriding and hiding goes away. The implicit conversions also go away. The built-in operator discussion changes: the built-in operators become the members of those System types.

Do we want full fidelity in both versions? If not, how much hand-waving for temporary C# 9 behavior do we allow?

I favor full fidelity. I'm not sure we can call them aliases of the same type and place exceptions on them; wouldn't that effectively be making them separate types?

Something we didn't discuss in the meeting is that the C# 11 feature is only available on some runtimes. At the top of the C# 11 spec:

The System.Runtime.CompilerServices.RuntimeFeature.NumericIntPtr runtime feature flag triggers this new behavior.

So it seems that even C# 11 still maintains nint as a separate type from IntPtr if the runtime doesn't support unifying. I'm getting more details on what exactly the runtime needs to be providing for the language feature to work; maybe just the definition of new members on (U)IntPtr? Maybe behavioral changes (see the Breaking Changes section)?

What will the C# spec do in 11 then? Keep the feature "bimodal" forever, or assume that C# 11 requires .NET 7?

Update: I've raised the same question, but a more time-pressing version of it, at #1532

## 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
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
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.

Comment on lines 762 to 766
Conversion from `A` to `Nullable<B>` is:

- an implicit nullable conversion if there is an identity conversion or implicit conversion from `A` to `B`;
- an explicit nullable conversion if there is an explicit conversion from `A` to `B`;
- otherwise, invalid.
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of adding this new section and the new letters A and B, what if we took this section above:

- An implicit or explicit conversion from `S?` to `T?`
- An implicit or explicit conversion from `S` to `T?`
- An explicit conversion from `S?` to `T`.

And augmented it thus:

- A conversion from `S?` to `T?`, implicit if the conversion from `S` to `T` is implicit, otherwise explicit
- A conversion from `S` to `T?`, implicit if the conversion from `S` to `T` is implicit, otherwise explicit
- A conversion from `S?` to `T`, always explicit

I think "invalid" is implied; when no conversion exists from S to T, we will not have gotten anywhere in this section.

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree in principle with @jnm2 above but the wording of his suggestion does not read well this non-american as it is missing small words 😉. If there is consensus that 749-751 are not clear then I’ll offer instead:

- A matching implicit or explicit conversion from `S?` to `T?`
- A matching implicit or explicit conversion from `S` to `T?`
- An explicit conversion from `S?` to `T`.

Either way the added lines are redundant:

Suggested change
Conversion from `A` to `Nullable<B>` is:
- an implicit nullable conversion if there is an identity conversion or implicit conversion from `A` to `B`;
- an explicit nullable conversion if there is an explicit conversion from `A` to `B`;
- otherwise, invalid.

**This subclause is informative.**

Unary numeric promotion occurs for the operands of the predefined `+`, `-`, and `~` unary operators. Unary numeric promotion simply consists of converting operands of type `sbyte`, `byte`, `short`, `ushort`, or `char` to type `int`. Additionally, for the unary – operator, unary numeric promotion converts operands of type `uint` to type `long`.
Unary numeric promotion occurs for the operands of the predefined `+`, ``, and `~` unary operators. Unary numeric promotion simply consists of converting operands of type `sbyte`, `byte`, `short`, `ushort`, or `char` to type `int`. Additionally, for the unary – operator, unary numeric promotion converts operands of type `uint` or `nint` to type `long`.
Copy link
Contributor

Choose a reason for hiding this comment

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

Is the en dash used when referring to the operator, despite the fact that the syntax for the operator must use a hyphen?

Copy link
Member Author

Choose a reason for hiding this comment

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

No, that must have snuck in in another PR.

Comment on lines 7026 to 7036
A constant expression shall either have the value `null` or one of the following types:
A constant expression may be either a value type or a reference type. If a constant expression has a value type, that type shall be one of the following: `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `nint`, `nuint`, `long`, `ulong`, `char`, `float`, `double`, `decimal`, `bool,` or any enumeration type. If a constant expression has a reference type, the expression shall:

- have a value of type `string`;
- have a value of `null`; or
- be a default value expression ([§12.8.21](expressions.md#12821-default-value-expressions)) of reference type.
Copy link
Contributor

Choose a reason for hiding this comment

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

This change no longer permits a constant expression of null of a nullable value type, which would make the following code invalid:

class C
{
    void M(int? x = null) { }
}

https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#15621-general:

An input parameter may have a default_argument. The expression in a default_argument shall be one of the following:

  • a constant_expression
  • an expression of the form new S() where S is a value type
  • an expression of the form default(S) where S is a value type


If any `nint`/`nuint` values are not representable as `Int32`/`UInt32`, or the run-time evaluation of the whole expression would throw an exception, then a compile-time error shall be produced.

> *Note*: These rules mean that an expression involving native integers which is superficially valid as a *constant_expression* may only be valid as an *expression* evaluated at runtime using the full implementation-defined native integer precision. *end note*
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd love to see an example!

Copy link
Member Author

Choose a reason for hiding this comment

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

Added in the next commit. (Also changed note to an example)

- treat all values of type `nuint` as `System.UInt32`;
- and otherwise use the same evaluation rules as for run-time non-constant expressions.

If any `nint`/`nuint` values are not representable as `Int32`/`UInt32`, or the run-time evaluation of the whole expression would throw an exception, then a compile-time error shall be produced.
Copy link
Contributor

Choose a reason for hiding this comment

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

Aren't all nint/nuint values within a constant expression representable as Int32/UInt32, given this line above?

A constant_expression of type nint shall have a value in the range [int.MinValue,int.MaxValue]. A constant_expression of type nuint shall have a value in the range [uint.MinValue,uint.MaxValue].

Copy link
Member Author

Choose a reason for hiding this comment

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

This is saying two different things, I think: First that any value on the RHS of a constant expression must be in valid range. The second is saying that the compiler must evaluate the full expression at compile time and store the value. If the result of that compile time evaluation is out of range, the compiler emits an error.

@BillWagner BillWagner force-pushed the v9-native-sized-integers branch from d9fd9bd to 6b62227 Compare January 16, 2026 16:06
@Nigel-Ecma
Copy link
Contributor

(Quoting as this is coming some way down the conversation)

There's an interesting time discussion: The changes to the feature will remove quite a bit of language from the standard. Once the keywords nint and nuint are synonyms for System.IntPtr and System.UIntPtr, the text for overloading, overriding and hiding goes away. The implicit conversions also go away. The built-in operator discussion changes: the built-in operators become the members of those System types.
Do we want full fidelity in both versions? If not, how much hand-waving for temporary C# 9 behavior do we allow?

I favor full fidelity. I'm not sure we can call them aliases of the same type and place exceptions on them; wouldn't that effectively be making them separate types?

Something we didn't discuss in the meeting is that the C# 11 feature is only available on some runtimes. At the top of the C# 11 spec:

The System.Runtime.CompilerServices.RuntimeFeature.NumericIntPtr runtime feature flag triggers this new behavior.

So it seems that even C# 11 still maintains nint as a separate type from IntPtr if the runtime doesn't support unifying. I'm getting more details on what exactly the runtime needs to be providing for the language feature to work; maybe just the definition of new members on (U)IntPtr? Maybe behavioral changes (see the Breaking Changes section)?

What will the C# spec do in 11 then? Keep the feature "bimodal" forever, or assume that C# 11 requires .NET 7?

Update: I've raised the same question, but a more time-pressing version of it, at #1532

See my reply above, I think this might be a question not of “fidelity” but of implementation-specific material sneaking into this PR.

We are certainly not going to be saying in the Standard that C#11 requires .NET 7 as C# does not require any version of .NET at all.

Copy link
Contributor

@Nigel-Ecma Nigel-Ecma left a comment

Choose a reason for hiding this comment

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

A lot of changes seem to be required, but what they are will require some work. See the one comment under this review.

Comment on lines 322 to 324
Although `nint` and `nuint` shall be represented by the types `System.IntPtr` and `System.UIntPtr`, respectively, `nint` and `nuint` are *not* aliases for those types. As such, not all members of the corresponding `System` types are defined for `nint` and `nuint`. Instead, the compiler shall make available additional conversions, unary operators (§12.9) and arithmetic operators (§12.12) for the types `System.IntPtr` and `System.UIntPtr` when used in the context of native integer types.

While the language provides operations and conversions for `nint` and `nuint` that are appropriate for integer types, those operations and conversions are not available on the `System` type counterparts. For example,
Copy link
Contributor

Choose a reason for hiding this comment

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

These few lines give rise to a few questions:

Although nint and nuint shall be represented by the types System.IntPtr and System.UIntPtr, respectively, nint and nuint are not aliases for those types. As such, not all members of the corresponding System types are defined for nint and nuint.

This seems to say there are members defined on IntPtr & UIntPtr that are explicitly not accessible via objects/values of type nint & nuint.

So is the deviation of nint & nuint from the other numeric types the restriction that not all members of the System.X type used for them may be accessed whether those members?

Remember under the conformance rules an implementation may provide types with additional members which are then accessible, are these native types avoiding that by not being “aliases“?

Instead, the compiler shall make available additional conversions, unary operators (§12.9) and arithmetic operators (§12.12) for the types System.IntPtr and System.UIntPtr when used in the context of native integer types.

First, and obviously, the “compiler” shall do not such thing – the language defines the operators, e.g. §12.10.5 (v7):

The predefined addition operators are listed below. For numeric and enumeration types, the predefined addition operators compute the sum of the two operands.

Where in the Standard does it ever state that these predefined operators are members of the “aliased” System.X type?

What difference is being asserted here that the “compiler” is making available that the language doesn’t for the other numeric types?

From a language perspective there are very few required members of any of numeric types. Take a look at System.Int and in §C no members are listed, look at the adopted spec from the CLI and it contains: 2 fields (min & max values), 2 compare methods, 2 equality methods, 1 hash code method, 4 parsing methods, and 4 conversions to string. What isn’t there is more notable than what is, e.g. not a single operator.

While the language provides operations and conversions for nint and nuint that are appropriate for integer types, those operations and conversions are not available on the System type counterparts.

So how does that differ from System.Int above, it also has no operators…

Now today .NET’s System.Int does, for example, implement IAdditionOperators<TSelf,TOther,TResult> which provides and addition operator but it is not in the C# Standard and use Roslyn to add to integers and it does not call it – nothing has changed, the language defines the operators, the implementation implements them using the features of its target architecture (for Roslyn compiling C#9 the CLR’s add for both int and nint).

So what is different about nint and nuint that needs to go into the Standard (v9 & v11)? At present this PR has no native int operators listed in §12.10.5 (v7) which seems rather key, but does have stuff about the compiler making additional things available which seems entirely irrelevant.

Looking at the source material linked at the top of the PR it is clear it is heavily implementation specific, going as far as listing CLR instructions.

All the implementation specific stuff picked up from the source material needs to be elided, and the core of the C# languages changes found in what is left – and once that is done I suspect the differences between C#9 & C#11 will be much reduced.

@Nigel-Ecma Nigel-Ecma self-requested a review February 4, 2026 03:58
Copy link
Contributor

@Nigel-Ecma Nigel-Ecma left a comment

Choose a reason for hiding this comment

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

This is hopefully getting close. It is pleasing to see that the differences between being aliases of & represented by are really minimal so the step to C#11 will be small.

Comment on lines 762 to 766
Conversion from `A` to `Nullable<B>` is:

- an implicit nullable conversion if there is an identity conversion or implicit conversion from `A` to `B`;
- an explicit nullable conversion if there is an explicit conversion from `A` to `B`;
- otherwise, invalid.
Copy link
Contributor

Choose a reason for hiding this comment

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

I agree in principle with @jnm2 above but the wording of his suggestion does not read well this non-american as it is missing small words 😉. If there is consensus that 749-751 are not clear then I’ll offer instead:

- A matching implicit or explicit conversion from `S?` to `T?`
- A matching implicit or explicit conversion from `S` to `T?`
- An explicit conversion from `S?` to `T`.

Either way the added lines are redundant:

Suggested change
Conversion from `A` to `Nullable<B>` is:
- an implicit nullable conversion if there is an identity conversion or implicit conversion from `A` to `B`;
- an explicit nullable conversion if there is an explicit conversion from `A` to `B`;
- otherwise, invalid.

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.
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.

> *Note*: The `char` type cannot be used as an underlying type, either by keyword or via an `integral_type_name`. *end note*
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this Note also now cover nint & nuint? I think the note borderline as it the text:

The underlying type shall be one of the integral types (§8.3.6) other than nint, nuint, and char. The underlying type may be specified either by an integral_type (§8.3.5), or an integral_type_name.

seems fairly clear, so dropping rather than updating would also be fine.

Copy link
Member Author

Choose a reason for hiding this comment

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

removing the note in the next commit.

Comment on lines 310 to +314
- If either operand is of type `decimal`, the other operand is converted to type `decimal`, or a binding-time error occurs if the other operand is of type `float` or `double`.
- Otherwise, if either operand is of type `double`, the other operand is converted to type `double`.
- Otherwise, if either operand is of type `float`, the other operand is converted to type `float`.
- Otherwise, if either operand is of type `ulong`, the other operand is converted to type `ulong`, or a binding-time error occurs if the other operand is of `type sbyte`, `short`, `int`, or `long`.
- Otherwise, if either operand is of type `ulong`, the other operand is converted to type `ulong`, or a binding-time error occurs if the other operand is of type `sbyte`, `short`, `int`, `nint`, or `long`.
- Otherwise, if either operand is of type `nuint`, the other operand is converted to type `nuint`, or a binding-time error occurs if the other operand is of type `sbyte`, `short`, `int`, `nint`, or `long`.
Copy link
Contributor

Choose a reason for hiding this comment

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

@jnm2: I think it can probably be simplified along the lines you suggest and avoid the lists. Maybe use letters as typical, e.g. let the two operands have types S & T. If S and T are the same type no promotion is required. If S implicitly converts to T then the first arg is promoted, if T to S then the second. Does the case if S & T are both implicitly convertible to R cover the case on line 316?

I’ll leave the wordsmithing to you (or others) 🙂

RexJaeschke and others added 15 commits February 26, 2026 16:17
Add support for native-sized integers

Add support for native-sized integers

Add support for native-sized integers

Add support for native-sized integers

Add support for native-sized integers

Add support for native-sized integers

Add support for native-sized integers

Add support for native-sized integers

fix example name

correct link

fix md formatting

fix formatting

fix md formatting

made minor tweaks

Add 2 new types

make minor tweak

Add native types to pointer indexing

Update standard/expressions.md

Co-authored-by: Kalle Olavi Niemitalo <kon@iki.fi>

Update standard/expressions.md

Co-authored-by: Kalle Olavi Niemitalo <kon@iki.fi>

Add support for native-sized integers

fix missing commit
-  #1060 (comment):  Take Nigel's suggestion, with minor wordsmithing.
- #1060 (comment) No change in this PR. Addressed with Rex's work on Annex C.
- For #1060 (comment): Use Nigel's suggestion.
- For #1060 (comment): Took Nigel's suggestion.
- #1060 (comment) No change. Deferred to when we address #729
Proofread and edit pass.
Co-authored-by: Joseph Musser <me@jnm2.com>
Rework the language in types with respect to `nint` and `nuint`. Focus on the language semantics, not the implementation based on `System.IntPtr` and `System.UIntPtr`.
Add text to specify the predefined operators for the `nint` and `nuint` types.
Co-authored-by: Joseph Musser <me@jnm2.com>
Co-authored-by: Nigel-Ecma <6654683+Nigel-Ecma@users.noreply.github.com>
@BillWagner BillWagner force-pushed the v9-native-sized-integers branch from cedda43 to 1b6c859 Compare February 26, 2026 21:17
BillWagner and others added 11 commits February 26, 2026 16:18
Co-authored-by: Nigel-Ecma <6654683+Nigel-Ecma@users.noreply.github.com>
Co-authored-by: Nigel-Ecma <6654683+Nigel-Ecma@users.noreply.github.com>
Co-authored-by: Nigel-Ecma <6654683+Nigel-Ecma@users.noreply.github.com>
1. Arithmetic operator code blocks (all add nint/nuint between uint/ulong and long/ulong lines):
   - added nint operator *(nint x, nint y); and nuint operator *(nuint x, nuint y);
   - added nint/nuint division operators
   - added nint/nuint remainder operators
   - added nint/nuint addition operators
   - added nint/nuint subtraction operators (also fixed missing closing paren on ulong line)
2. Shift operator code blocks:
   - added nint operator <<(nint x, int count); and nuint operator <<(nuint x, int count);
   - added nint operator >>(nint x, int count); and nuint operator >>(nuint x, int count);
3. Unary minus operator:
    - added nint operator –(nint x);
    - updated to mention nint: "(−2³¹ for int, the corresponding value for nint, or −2⁶³ for long)"
1. Removed or \nint`from the unary numeric promotion rule in §12.4.7.2 Since there is now a predefinednint operator -(nint x), nintshould not be promoted tolong`.

1.  Add the S₁ is nint and S₂ is nuint or ulong entry in the better conversion target list
Changed from "A constant expression may be either a value type or a reference type" (with null only under the reference type branch) to "A constant expression shall have the value null, or be of a value type or a reference type." This hoists null to the top level so it's valid regardless of target type — covering nullable value type defaults like void M(int? x = null). Removed the now-redundant null bullet from the reference type list.
1. Fixed missing opening backtick on `System.IntPtr`.
2. Fixed grammar from "In context if type resolution (§7.8.1) on either of these names succeeds then that name shall be recognised" to "If type resolution (§7.8.1) on either of these names succeeds, that name shall be recognised".
3. Added "native signed precision, or native unsigned precision" to the operator precision list, and added a note clarifying that native precision means 32-bit or 64-bit depending on platform and that nint/nuint operators use native precision rather than being promoted.
This fixes an old bulk change.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

meeting: discuss This issue should be discussed at the next TC49-TG2 meeting Review: pending Proposal is available for review type: feature This issue describes a new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants