Skip to content

Add support for native-sized integers #1060

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 21 commits into
base: draft-v9
Choose a base branch
from

Conversation

RexJaeschke
Copy link
Contributor

@RexJaeschke RexJaeschke commented Mar 17, 2024

IMPORTANT: There are two related MS proposals for native integer support: V9’s Native-sized integers and V11’s Numeric IntPtr.

  • V9 introduces nint and nunint as two new types, which while required to map directly to System.IntPtr and System.UIntPtr, respectively, these new types are not synonyms for those underlying types. (They are, however, made synonyms in V11.)

  • In V9 there are no predefined operators taking native integer types, and that instead implicit conversions are done to match the existing predefined operators. And that the predefined operators are added in V11.

The MS V11 spec appears to also include lots of edits that need to be applied to V9. For example, Rex took all the V11 conversion edits and put them in V9. And he ignored most stuff about operators in the MS V9 spec as it applies only to V11 )(and the MS V11 spec reflects that).

Open Issue: It is likely that 12.6.4.7, "Better conversion target" is impacted by this feature addition; however, I was not able to determine how nint and nuint fit in there.

Open Issue: While researching this, I noticed that 12.4.7, “Numeric promotions” and its subsections are all marked as being informative. If so, where is this stuff stated/implied normatively? This would be OK if that content were stated (or implied) in some other, normative, place, but where is that? In any event, the supposedly informative text, “Binary numeric promotion consists of applying the following rules, in the order they appear here:” sure sounds normative to me!

@RexJaeschke RexJaeschke added the type: feature This issue describes a new feature label Mar 17, 2024
@RexJaeschke RexJaeschke added this to the C# 9.0 milestone Mar 17, 2024
@RexJaeschke RexJaeschke marked this pull request as draft March 17, 2024 20:32
@@ -315,7 +321,7 @@ This implicit conversion seemingly violates the advice in the beginning of [§10

An implicit constant expression conversion permits the following conversions:

- A *constant_expression* ([§12.23](expressions.md#1223-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.23](expressions.md#1223-constant-expressions)) of type `int` can be converted to type `sbyte`, `byte`, `short`, `ushort`, `uint`, `nint`, `nuint`, or `ulong`, provided the value of the *constant_expression* is within the range of the destination type.
Copy link
Contributor

@KalleOlaviNiemitalo KalleOlaviNiemitalo May 12, 2025

Choose a reason for hiding this comment

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

The conversion from int to nint is already allowed in 10.2.3 Implicit numeric conversions; the int value is always within the range of nint. I don't think the conversion from int to nint should be mentioned here in 10.2.11 Implicit constant expression conversions.

@@ -310,10 +312,12 @@ Binary numeric promotion occurs for the operands of the predefined `+`, `-`, `*`
- 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`.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
- 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 `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`.

@@ -3273,7 +3279,7 @@ A *default_value_expression* is a constant expression ([§12.23](expressions.md#

- a reference type
- a type parameter that is known to be a reference type ([§8.2](types.md#82-reference-types));
- one of the following value types: `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `char`, `float`, `double`, `decimal`, `bool,`; or
- one of the following value types: `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `nint`, `nuint`, `long`, `ulong`, `char`, `float`, `double`, `decimal`, `bool,`; or
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
- one of the following value types: `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `nint`, `nuint`, `long`, `ulong`, `char`, `float`, `double`, `decimal`, `bool,`; or
- one of the following value types: `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `nint`, `nuint`, `long`, `ulong`, `char`, `float`, `double`, `decimal`, `bool`; or

Regardless of whether commas should be inside or outside the backticks, this comma is surely subsumed by the semicolon.

@@ -6748,11 +6756,9 @@ constant_expression
;
```

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, that type shall be `string`, a default value expression ([§12.8.21](expressions.md#12821-default-value-expressions)) for some reference type, or the value of the expression shall be `null`.
Copy link
Contributor

Choose a reason for hiding this comment

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

"that type shall be […] a default value expression" doesn't make sense to me; a type is not an expression.

The value of a default value expression for a reference type is null anyway so I don't think default value expressions need to be explicitly mentioned here. OTOH this oddity is already there before this pull request.

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 with @KalleOlaviNiemitalo, I'll offer the following – feel free to wordsmith:

Suggested change
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, that type shall be `string`, a default value expression ([§12.8.21](expressions.md#12821-default-value-expressions)) for some reference type, or the value of the expression shall be `null`.
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.

public override bool Equals(object obj);
public override int GetHashCode();
public override string ToString();
public string ToString(string format);
Copy link
Contributor

@KalleOlaviNiemitalo KalleOlaviNiemitalo May 12, 2025

Choose a reason for hiding this comment

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

System.IntPtr and System.UIntPtr are declared in §C.3 Standard Library Types not defined in ISO/IEC 23271, but they do not have ToString(string) methods there.

@@ -151,7 +151,7 @@ Delegate types are described in [§20](delegates.md#20-delegates).

### 8.3.1 General

A value type is either a struct type or an enumeration type. C# provides a set of predefined struct types called the ***simple types***. The simple types are identified through keywords.
A value type is either a struct type or an enumeration type. C# provides a set of predefined struct types called the ***simple types***. The simple types are identified through keywords and contextual keywords.
Copy link
Contributor

Choose a reason for hiding this comment

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

§6.4.4 Keywords says

A contextual keyword is an identifier-like sequence of characters that has special meaning in certain contexts, but is not reserved, and can be used as an identifier outside of those contexts as well as when prefaced by the @ character.

but this PR does not specify those "certain contexts" in which nint and nuint have special meaning.

@@ -6802,6 +6808,8 @@ Whenever an expression fulfills the requirements listed above, the expression is

The compile-time evaluation of constant expressions uses the same rules as run-time evaluation of non-constant expressions, except that where run-time evaluation would have thrown an exception, compile-time evaluation causes a compile-time error to occur.

Due to the implementation-defined nature of native integers ([§8.3.6](types.md#836-integral-types)), constant folding operations on `nint` and `nuint` operands shall be evaluated as if they had type `System.Int32` and `System.UInt32`, respectively. If the operation results in a constant value representable in 32 bits, constant folding may be performed at compile-time. Otherwise, the operation is executed at runtime and is not considered to be a constant.
Copy link
Contributor

Choose a reason for hiding this comment

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

“Constant folding” is an implementation optimisation term, it is in the source material only as it is describing the semantics by way of describing one particular implementation.

The semantics that need to be specified are that within a constant expression operations on native ints shall be evaluated as operations on 32-bit ints and if this conversion or runtime evaluation of the expression would have resulted in an exception then the expression is not a constant expression and a compile-time error shall be issued.

I'll offer as a starting point the following replacement for lines 6809-11 (git limitations don’t allow a “suggestion”):

The compile-time evaluation of a constant_expression shall:

  • treat all values of type nint as System.Int32;
  • 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.

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

I think this captures the semantics.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: feature This issue describes a new feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants