www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - What does a cast really do?

reply Quirin Schroll <qs.il.paperinik gmail.com> writes:
It seems a cast does more than change the static type and VRP.
```d
void foo(uint) { }

int x = -1;
foo(x); // compiles (debatable)
foo(long(x)); // compiles(!)
foo(cast(long)x); // compiles(!)
foo((() => cast(long)x)()); // Error: foo is not callable using 
argument types […]
```

Why do the latter two work? Their static type is `long` which 
normally rules out conversion to `uint`. However, if VRP can 
prove the value is definitely in the range of `uint`, the 
implicit conversion to `uint` is possible. However, VRP shouldn’t 
say that that’s the case, since `int` supports negative numbers 
and `uint` doesn’t.
Feb 20
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Thursday, February 20, 2025 6:02:26 PM MST Quirin Schroll via
Digitalmars-d-learn wrote:
 It seems a cast does more than change the static type and VRP.
 ```d
 void foo(uint) { }

 int x = -1;
 foo(x); // compiles (debatable)
 foo(long(x)); // compiles(!)
 foo(cast(long)x); // compiles(!)
 foo((() => cast(long)x)()); // Error: foo is not callable using
 argument types […]
 ```

 Why do the latter two work? Their static type is `long` which
 normally rules out conversion to `uint`. However, if VRP can
 prove the value is definitely in the range of `uint`, the
 implicit conversion to `uint` is possible. However, VRP shouldn’t
 say that that’s the case, since `int` supports negative numbers
 and `uint` doesn’t.
I don't think that VRP cares about negative vs positive due to the fact that the compiler implicitly converts between negative and positive integer types of the same size. For instance, uint i = -1; compiles just fine. I think that what it basically comes down to is that because -1 fits in int, and int implicitly converts to uint, VRP is fine with converting the long with a value of -1 to uint. So, as long as the value fits in 32 bits, the conversion will work even if gets screwed up by the conversion between signed and unsigned. - Jonathan M Davis
Feb 20
parent reply Paul Backus <snarwin gmail.com> writes:
On Friday, 21 February 2025 at 07:44:54 UTC, Jonathan M Davis 
wrote:
 I think that what it basically comes down to is that because -1 
 fits in int, and int implicitly converts to uint, VRP is fine 
 with converting the long with a value of -1 to uint. So, as 
 long as the value fits in 32 bits, the conversion will work 
 even if gets screwed up by the conversion between signed and 
 unsigned.
This has nothing to do with the value -1. You get the same result even if the value of x is completely unknown: void foo(uint) {} void example(int x) { foo(x); // compiles foo(long(x)); // compiles foo(cast(long) x); // compiles foo((() => cast(long) x)()); // Error: foo is not callable [...] } My best guess is that when VRP looks at `long(x)` or `cast(long) x`, it can see that x is an int, so it allows the value to be converted *back* to int (and then from int to uint). But that information is lost when you hide the cast expression inside a function call.
Feb 21
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On Friday, 21 February 2025 at 13:07:38 UTC, Paul Backus wrote:
 On Friday, 21 February 2025 at 07:44:54 UTC, Jonathan M Davis 
 wrote:
 I think that what it basically comes down to is that because 
 -1 fits in int, and int implicitly converts to uint, VRP is 
 fine with converting the long with a value of -1 to uint. So, 
 as long as the value fits in 32 bits, the conversion will work 
 even if gets screwed up by the conversion between signed and 
 unsigned.
This has nothing to do with the value -1. You get the same result even if the value of x is completely unknown: void foo(uint) {} void example(int x) { foo(x); // compiles foo(long(x)); // compiles foo(cast(long) x); // compiles foo((() => cast(long) x)()); // Error: foo is not callable [...] } My best guess is that when VRP looks at `long(x)` or `cast(long) x`, it can see that x is an int, so it allows the value to be converted *back* to int (and then from int to uint). But that information is lost when you hide the cast expression inside a function call.
Yes, VRP is a "value range". In this case, it knows that the long represented by the expression can only have the range int.min .. int.max inclusive. The issue seems to be that the type is irrelevant when considering the conversion to unsigned. `uint` apparently can accept any value from -int.min to uint.max, regardless of type, which is an odd allowance. But.... testing this, it doesn't make sense: ```d uint x = long(-1); // OK uint y = -1L; // Error: cannot implicitly convert expression `-1L` of type `long` to `uint` ``` Surely something here is worthy of a bug report? -Steve
Feb 21
parent Lance Bachmeier <no spam.net> writes:
On Friday, 21 February 2025 at 15:48:12 UTC, Steven Schveighoffer 
wrote:

 But.... testing this, it doesn't make sense:

 ```d
 uint x = long(-1); // OK
 uint y = -1L; // Error: cannot implicitly convert expression 
 `-1L` of type `long` to `uint`
 ```

 Surely something here is worthy of a bug report?

 -Steve
This compiles too: ``` uint y = double(-1); writeln(y); // 4294967295 ```
Feb 21