Bug 1878 – foreach does not handle integral types appropriately
Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
x86
OS
Linux
Creation time
2008-02-28T15:01:00Z
Last change time
2015-05-28T21:43:29Z
Keywords
rejects-valid
Assigned to
nobody
Creator
andrei
Comments
Comment #0 by andrei — 2008-02-28T15:01:41Z
ubyte limit = whatever();
ubyte x;
foreach (e; 0 .. limit)
x = e;
does not compile with warnings enabled. The compiler should recognize that a compile-time constant (in this case 0) is passed in and choose the tightest type (in this case ubyte) for iteration.
Comment #1 by andrej.mitrovich — 2012-10-28T16:06:36Z
I think a language change might end up breaking code which assumes the index variable is always size_t.
The simplest workaround is to type the index variable:
foreach (ubyte e; 0 .. limit)
writeln(e);
Otherwise if we want type inference we could implement a library function:
import std.stdio;
struct Walk(T)
{
T idx;
T max;
@property T front() { return idx; }
@property void popFront() { ++idx; }
@property bool empty() { return !(idx < max); }
}
auto walk(L, U)(L lwr, U upr)
{
assert(lwr <= U.max);
return Walk!U(cast(U)lwr, upr);
}
void main()
{
ubyte limit = 10;
ubyte x;
foreach (e; walk(0, limit))
{
writefln("%s %s", typeid(e), e); // type is ubyte
}
}
Comment #2 by bearophile_hugs — 2012-10-28T16:32:52Z
A wider benchmark:
import std.typetuple: TypeTuple;
import std.range: iota;
void main() {
foreach (T; TypeTuple!(byte, ubyte, short, ushort,
int, uint, long, ulong))
foreach (i; 0 .. cast(T)10)
pragma(msg, T, " ", typeof(i));
pragma(msg, "");
foreach (T; TypeTuple!(byte, ubyte, short, ushort,
int, uint, long, ulong))
foreach (i; iota(0, cast(T)10))
pragma(msg, T, " ", typeof(i));
}
byte int
ubyte int
short int
ushort int
int int
uint uint
long long
ulong ulong
byte int
ubyte int
short int
ushort int
int int
uint uint
long long
ulong ulong
Comment #3 by lio+bugzilla — 2013-09-08T01:42:44Z
This bug is also the source of many false positives when bug 259 gets fixed.
The problem is that ForeachRangeStatement is using typeCombine, which does the C style integer promotion. It should probably use the ?: combine logic instead.
Comment #4 by lio+bugzilla — 2013-09-08T02:14:15Z
I checked the difference between CondExp (?:) and ForeachRangeStatement. The former only has a special case when the types of the two expressions are equal. It would fix foreach(i;ubyte..ubyte) and similar, but would not address the issue raised by the OP.
It's still worth merging the logic of CondExp with ForeachRangeStatement, though, if only for predictability. In fact, a?0:ubyte should similarly not evaluate to 'int' but to 'ubyte', for the exact same reasons.
https://github.com/D-Programming-Language/dmd/pull/2538
Comment #5 by github-bugzilla — 2013-09-12T22:03:13Z