Re: What does a cast really do?

2025-02-21 Thread Steven Schveighoffer via Digitalmars-d-learn

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


Re: What does a cast really do?

2025-02-21 Thread Lance Bachmeier via Digitalmars-d-learn
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
```


Re: What does a cast really do?

2025-02-21 Thread Paul Backus via Digitalmars-d-learn
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.


Re: What does a cast really do?

2025-02-20 Thread Jonathan M Davis via Digitalmars-d-learn
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