Thread overview
[Issue 13228] Value range analysis for the length of slices
Dec 17, 2022
Iain Buclaw
July 30, 2014
https://issues.dlang.org/show_bug.cgi?id=13228

--- Comment #1 from bearophile_hugs@eml.cc ---
Beside allowing safe implicit casts as shown above, this feature is also able to catch slice-related bugs at compile time, like in this code:


int x = 11;
void main() {
    int[100] a;
    const b = a[5 .. 5 + x];
    int[10] c = b;
}


That in dmd 2.066beta5 compiles without errors, and throws an error at run-time:

object.Error@(0): Array lengths don't match for copy: 11 != 10

--
November 11, 2014
https://issues.dlang.org/show_bug.cgi?id=13228

--- Comment #2 from bearophile_hugs@eml.cc ---
I think simple cases like this could be supported by the same length range analysis:

void foo(int[7]) {}
void main() {
    int[3] a;
    int[2] b, c;
    foo(a ~ b ~ c); // No run-time length test here.
}



void foo(int[2]) {}
void main() {
    int[5] a;
    const int len = 2;
    foo(a[0 .. len]); // OK
    const int[] b = new int[2];
    foo(a[0 .. b.length]); // Currently an error
}



Here the run-time test of the length of 'a' can be omitted, because it can't be longer than 'b':

int n = 8;
void main() {
    const a = new int[n % 5];
    int[10] b;
    b[0 .. a.length] = 0;
}

--
November 11, 2014
https://issues.dlang.org/show_bug.cgi?id=13228

Steven Schveighoffer <schveiguy@yahoo.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |schveiguy@yahoo.com

--- Comment #3 from Steven Schveighoffer <schveiguy@yahoo.com> ---
(In reply to bearophile_hugs from comment #0)
> I suggest to introduce in D a value range analysis and propagation for the length of slices, it should allow code like (currently refused):
> 
> 
> void foo(int[100]) {}
> ubyte x = 100;
> void main() {
>     const int[] a = new int[x];
>     foo(a);
> }
> 
> 
> That currently gives:
> 
> test.d(5,8): Error: function test.foo (int[100] _param_0) is not callable
> using argument types (const(int[]))

static this()
{
  x = 99;
}

oops...

> 
> 
> That is comparable to code like this (that is accepted by dmd 2.066beta5):
> 
> void foo(ubyte) {}
> ubyte x = 100;
> void main() {
>     const int a = x;
>     foo(a);
> }

This is not the same, because a's value isn't known at compile time, just its range.

This ER is asking for flow analysis, which I think is not on the table. Be mindful of what the compiler can know at compile time. Value range analysis for expressions dies at the end of an expression.

--
November 11, 2014
https://issues.dlang.org/show_bug.cgi?id=13228

--- Comment #4 from bearophile_hugs@eml.cc ---
(In reply to Steven Schveighoffer from comment #3)

> This is not the same, because a's value isn't known at compile time, just its range.

You are probably right, that example seems bad. Sorry, and thank you for spotting the problem.


> This ER is asking for flow analysis, which I think is not on the table.

According to Walter flow analysis is on the table for the future of D. But this ER doesn't want to ask for flow flow analysis (it's meant to work similarly to the current value range analysis. See also below). If this ER seems to ask for flow analysis then I have done a mistake in an example, or I have confused ideas :-)


> Value range analysis for expressions dies at the end of an expression.

This is not longer true, this compiles:

uint x = 10;
void main() {
    immutable uint y = x % 100;
    ubyte z = y; // No errors here.
}


Now the value range of run-time immutable values is carried beyond the end of an expression.

--
November 12, 2014
https://issues.dlang.org/show_bug.cgi?id=13228

--- Comment #5 from Steven Schveighoffer <schveiguy@yahoo.com> ---
(In reply to bearophile_hugs from comment #4)
> (In reply to Steven Schveighoffer from comment #3)
> 
> > This ER is asking for flow analysis, which I think is not on the table.
> 
> According to Walter flow analysis is on the table for the future of D. But this ER doesn't want to ask for flow flow analysis (it's meant to work similarly to the current value range analysis. See also below). If this ER seems to ask for flow analysis then I have done a mistake in an example, or I have confused ideas :-)

I think your original example is not valid, as I have shown x can change before main is called. But in general, I don't think main should be treated specially by the compiler in terms of execution order.

Your example in comment 1 also suffers from the same issue.

The idea of avoiding runtime checks for array lengths when the length is known at compile time is ok, but I think in general, this is not a large issue. It is an infrequent case where the compiler knows the length of slices and can avoid a runtime check.

One caveat to consider is that the result of a runtime call is defined by the runtime, not the compiler. Although the spec defines what should happen, I'm not certain it's worth eliding runtime checks for runtime code. For example, there could be an error in the runtime that returns the wrong thing for new int[2], and avoiding the runtime check will create other issues.

however, your 3rd example in comment 2 should be doable.

> > Value range analysis for expressions dies at the end of an expression.
> 
> This is not longer true, this compiles:
> 
> uint x = 10;
> void main() {
>     immutable uint y = x % 100;
>     ubyte z = y; // No errors here.
> }

I stand corrected, thanks for letting me know.

--
December 17, 2022
https://issues.dlang.org/show_bug.cgi?id=13228

Iain Buclaw <ibuclaw@gdcproject.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Priority|P1                          |P4

--
December 13
https://issues.dlang.org/show_bug.cgi?id=13228

--- Comment #6 from dlangBugzillaToGithub <robert.schadek@posteo.de> ---
THIS ISSUE HAS BEEN MOVED TO GITHUB

https://github.com/dlang/dmd/issues/18859

DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB

--