digitalmars.D.learn - A range analysis question
- bearophile (28/28) Jul 10 2013 Do you know why the assignment to 'item' is accepted in the first
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (11/39) Jul 10 2013 s[0][0] is known to be int 1 at compile time. It is also known that (1
- bearophile (8/13) Jul 10 2013 The result is supposed to fit in an ubyte because the input is
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (17/30) Jul 10 2013 Not in either of the two cases that I have given:
- bearophile (10/18) Jul 10 2013 Adding a bit more static analysis to D will help making D a bit
- bearophile (19/20) Jul 11 2013 Thinking some more about this topic I have created a small test
- bearophile (3/4) Jul 11 2013 http://d.puremagic.com/issues/show_bug.cgi?id=10615
Do you know why the assignment to 'item' is accepted in the first case and refused in the second? ubyte generate1(s...)() { ubyte[10] result; foreach (immutable i, ref item; result) item = s[0][0] << 4; return result[0]; } ubyte generate2(s...)() { ubyte[10] result; foreach (immutable i, ref item; result) item = s[0][i % 3] << 4; // line 11 return result[0]; } void main() { enum ubyte[16] data = [1, 2, 3, 4]; auto g1 = generate1!data; auto g2 = generate2!data; } dmd gives: test.d(11): Error: cannot implicitly convert expression (cast(int)[cast(ubyte)1u, cast(ubyte)2u, cast(ubyte)3u, cast(ubyte)4u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u][i % 3u] << 4) of type int to ubyte Bye and thank you, bearophile
Jul 10 2013
On 07/10/2013 03:08 PM, bearophile wrote:Do you know why the assignment to 'item' is accepted in the first case and refused in the second? ubyte generate1(s...)() { ubyte[10] result; foreach (immutable i, ref item; result) item = s[0][0] << 4;s[0][0] is known to be int 1 at compile time. It is also known that (1 << 4) can fit in a ubyte by value range propagation. dmd is being helpful. Change the code so that the result does not fit a ubyte you will get the same error as in line 11. a) Shift by 8 instead of 4 b) Change the value in main to something like 42return result[0]; } ubyte generate2(s...)() { ubyte[10] result; foreach (immutable i, ref item; result) item = s[0][i % 3] << 4; // line 11That foreach is a runtime foreach because it is applied on 'result' as opposed to the type tuple 's'. Apparently the compiler does not do that kind of code analysis.return result[0]; } void main() { enum ubyte[16] data = [1, 2, 3, 4]; auto g1 = generate1!data; auto g2 = generate2!data; } dmd gives: test.d(11): Error: cannot implicitly convert expression (cast(int)[cast(ubyte)1u, cast(ubyte)2u, cast(ubyte)3u, cast(ubyte)4u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u][i % 3u] << 4) of type int to ubyte Bye and thank you, bearophileAli
Jul 10 2013
Ali Çehreli:Change the code so that the result does not fit a ubyte you will get the same error as in line 11.The result is supposed to fit in an ubyte because the input is supposed to be made of nibbles. (I have tried to add asserts or tests, but they don't change the situation, so I have omitted them here).That foreach is a runtime foreach because it is applied on 'result' as opposed to the type tuple 's'. Apparently the compiler does not do that kind of code analysis.Right, but is it right to ask for such analysis to be performed? Bye, bearophile
Jul 10 2013
On 07/10/2013 04:10 PM, bearophile wrote:Ali Çehreli:Not in either of the two cases that I have given: a) (1 << 8) would not fit a ubyte b) (42 << 4) would not fit a ubyte Of course we are reminded again that even if 1 and 42 are ubytes, the result of the << operator is int. So you first expression (1 << 4) is an int which happens to fit a ubyte and that line compiles.Change the code so that the result does not fit a ubyte you will get the same error as in line 11.The result is supposed to fit in an ubyte because the input is supposed to be made of nibbles.(I have tried to add asserts or tests, but they don't change the situation, so I have omitted them here).That would be great but there are many other cases where the compiler does not do anything like that. Here, it would have to decide similar to "even though this is a runtime foreach, I know at compile time that 'result' is a fixed-length array so 'i' is between 0 and 10. I also have this compile-time tuple template parameters. Now let me see whether running that code would produce values that would fit the 'result's type ubyte." I don't think we are there yet. :)That foreach is a runtime foreach because it is applied on 'result' as opposed to the type tuple 's'. Apparently the compiler does not do that kind of code analysis.Right, but is it right to ask for such analysis to be performed?Bye, bearophileAli
Jul 10 2013
Ali Çehreli:That would be great but there are many other cases where the compiler does not do anything like that. Here, it would have to decide similar to "even though this is a runtime foreach, I know at compile time that 'result' is a fixed-length array so 'i' is between 0 and 10. I also have this compile-time tuple template parameters. Now let me see whether running that code would produce values that would fit the 'result's type ubyte." I don't think we are there yet. :)Adding a bit more static analysis to D will help making D a bit more modern language. Having something like "liquid types" is very good, but I think that even much more limited capabilities are enough to avoid avoid some casts and bugs. Recently I have added a related (simple) enhancement request, perhaps it's implementable: http://d.puremagic.com/issues/show_bug.cgi?id=10594 Bye, bearophile
Jul 10 2013
Ali Çehreli:I don't think we are there yet. :)Thinking some more about this topic I have created a small test example: uint i = 100; void main(in string[] args) { auto j = args.length; ubyte x1 = (i ^^ 2) % 256; // OK ubyte x2 = (i ^^ 3) % 256; // OK ubyte[] arr = [(i ^^ 2) % 256, (i ^^ 3) % 256]; // OK! ubyte y = [(i ^^ 2) % 256, (i ^^ 3) % 256][j]; // Error } The lines with x1 and x2 are accepted, because the range analysis is able to infer those are in-range assignments. While the assignment of y is refused, despite all the contents of the array can be inferred as castable to ubyte, as shown in assignment of arr. I think this (the line with y) is worth an enhancement request. Bye, bearophile
Jul 11 2013
I think this (the line with y) is worth an enhancement request.http://d.puremagic.com/issues/show_bug.cgi?id=10615 Bye, bearophile
Jul 11 2013