- Notifications
You must be signed in to change notification settings - Fork92
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
base:draft-v9
Are you sure you want to change the base?
Add support for native-sized integers#1060
Uh oh!
There was an error while loading.Please reload this page.
Conversation
@@ -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. |
KalleOlaviNiemitaloMay 12, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
The conversion fromint
tonint
is already allowed in 10.2.3 Implicit numeric conversions; theint
value is always within the range ofnint
. I don't think the conversion fromint
tonint
should be mentioned here in 10.2.11 Implicit constant expression conversions.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
@@ -6748,11 +6756,9 @@ constant_expression | |||
; | |||
``` | |||
A constant expressionshalleitherhave thevalue`null`oroneof thefollowing types: | |||
A constant expressionmay beeithera value type or a reference type. If a constant expression has avaluetype, that type shall be one of the following: `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `nint`, `nuint`, `long`, `ulong`, `char`, `float`, `double`, `decimal`, `bool,`orany 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 valueof theexpression shall be `null`. |
There was a problem hiding this comment.
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 isnull
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.
There was a problem hiding this comment.
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:
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, orthevalue of theexpression 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); |
KalleOlaviNiemitaloMay 12, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
There was a problem hiding this comment.
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.3Standard Library Types not defined in ISO/IEC 23271, but they do not have ToString(string) methods there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Thanks,@KalleOlaviNiemitalo. I'm rethinking this listing of included/excluded members (which I took from the MS spec).§C.2 has declarations forIntPtr
andUIntPtr
withno members shown. Even though the CLI specdoes have members for each,none of those are required by Standard C, so we've omitted them until now. As such, it seems that I should remove the discussion and list of members that are explicitly excluded, as we've never acknowledged their existence previously, and there seems to be no good reason to do so now. (Or is there? See below.)
As for the implicitly included list, if we retain that as proposed, that would require adding those 4 members to C.2 (theyare defined in the CLI). If we do that, the 2 methods having parameters need to have a?
suffix added to those parameters .
@@ -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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
§6.4.4Keywords says
Acontextual 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 whichnint
andnuint
have special meaning.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
@KalleOlaviNiemitalo. The grammar rulevalue_type now allowsnint
andnuint
as alternatives, which gives all the situations in which these identifiersmight have special meaning. But not every such use of these identifiers designates those type names. For example,
classnint{}classTest{staticvoidM(){ninti=default;}}
How about I extend line 154 above with the following?
A value type is either a struct type or an enumeration type. C# provides a set of predefined struct types called thesimple types. The simple types are identified through keywords and contextual keywords.If the identifier
nint
(ornuint
) appears in the context of avalue_type and a declared type callednint
(ornuint
) is in scope, the declared name takes precedence over the use of the identifier as a contextual keyword.
Does that address your concern?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Does the term "declared type" include type parameters?
classC<uint>{voidM(uintp){}}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
The pattern used elsewhere in the Standard is to include a paragraph after the introduction of the grammar rule,value_type in this case, which states how the ambiguity is to be resolved. So at line 220 the following para can be inserted:
Because the names
nint
andnuint
are not keywords there is syntactic ambiguity between recognising them as atype_name or avalue_type. In context if type resolution (§7.8.1) on either of these names succeeds then that name shall be recognised as atype_name; otherwise it shall be recognised as avalue_type.
This para follows the pattern used elsewhere, e.g. fornotnull
(§15.2.5).
@@ -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. |
Nigel-EcmaMay 12, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
There was a problem hiding this comment.
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:
The compile-time evaluation of aconstant_expression shall:
- treat all values of type
nint
asSystem.Int32
;- treat all values of type
nuint
asSystem.UInt32
;- and otherwise use the same evaluation rules as for run-time non-constant expressions.
If any
nint
/nuint
values are not representable asInt32
/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 aconstant_expression may only be valid as anexpression evaluated at runtime using the full implementation-defined native integer precision.end note
I think this captures the semantics.
Co-authored-by: Kalle Olavi Niemitalo <kon@iki.fi>
Co-authored-by: Kalle Olavi Niemitalo <kon@iki.fi>
@@ -484,7 +484,7 @@ pointer_element_access | |||
; | |||
``` | |||
In a pointer element access of the form `P[E]`, `P` shall be an expression of a pointer type other than `void*`, and `E` shall be an expression that can be implicitly converted to `int`, `uint`, `long`, or `ulong`. | |||
In a pointer element access of the form `P[E]`, `P` shall be an expression of a pointer type other than `void*`, and `E` shall be an expression that can be implicitly converted to `int`, `uint`, `nint`, `nuint`, `long`, or `ulong`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
This reminds me about#729, whereP[E]
is used and the compile-time type ofE
isdynamic
. Will the runtime binder now have to consider a dynamic conversion tonint
, too?
Uh oh!
There was an error while loading.Please reload this page.
IMPORTANT: There are two related MS proposals for native integer support:V9’s Native-sized integers andV11’s Numeric IntPtr.
V9 introduces
nint
andnunint
as two new types, which whilerequired to map directly toSystem.IntPtr
andSystem.UIntPtr
, respectively, these new types arenot synonyms for those underlying types. (They are, however, made synonyms in V11.)In V9 there areno 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
andnuint
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!