Bug 4661 – Array Literal Incompatible Type Error Msg Should Include Line Number
Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P2
Component
phobos
Product
D
Version
D2
Platform
x86
OS
Windows
Creation time
2010-08-17T06:01:00Z
Last change time
2011-06-11T12:50:14Z
Keywords
diagnostic, patch
Assigned to
nobody
Creator
bearophile_hugs
Comments
Comment #0 by bearophile_hugs — 2010-08-17T06:01:25Z
Problem in building an array of lazy sequences. This D2 code:
import std.algorithm: map;
void main() {
auto r1 = map!q{a+1}([1, 2, 3]);
auto r2 = map!q{a+2}([1, 2, 3]);
auto a = [r1, r2];
}
Fails, and DMD 2.048 shows:
Error: incompatible types for ((r1) ? (r2)): 'Map!(result,int[])' and 'Map!(result,int[])'
Additionally, the error message lacks a line number.
Comment #1 by dsimcha — 2010-08-17T15:51:49Z
This bug is invalid because of the way template instantiation from string lambdas works. Instantiating map with q{a + 1} produces a completely different type than map instantiated with q{a + 2}, and therefore storing them in an array should not be possible. Take a look at how Map and std.functional.unaryFun() work. Also, to illustrate my point, note that the following code works:
import std.algorithm: map;
void main() {
auto r1 = map!q{a+1}([1, 2, 3]);
auto r2 = map!q{a+1}([1, 2, 3]);
auto a = [r1, r2];
}
Comment #2 by braddr — 2010-08-17T16:25:19Z
Take a step back and rethink your analysis. This example is a straight forward case of int[] to int[] mapping. They _should_ be compatible types. The map function is irrelevant to the types involved. If the result of the map functions differed, then you'd be right.
Also, the lack of a line number is a bug regardless of the validity of the operation.
Comment #3 by dsimcha — 2010-08-17T17:39:01Z
Ok, so this is a legit diagnostic bug. I'll grant you that. However, thinking that Map!("a + 1", Range) and Map!("a + 2", Range) are the same type represents a serious misunderstanding of template alias parameters. The binding of the lambda function to the Map instance happens at compile time, not runtime. Let's try a thought experiment, thinking at the C level. What would happen if Map!"a + 2" were cast to Map!"a + 1" and front() were called?
Map!"a + 1".front() would be called. Inlined (probably) in Map!"a + 1".front() is something like return _input.front + 1.
Comment #4 by braddr — 2010-08-17T17:46:40Z
You're miring your logic in the implementation rather than the concept of what map is. Pretend it was implemented as:
T[] map(T)(mapfunc, T[]);
would we even be having this discussion?
Comment #5 by dsimcha — 2010-08-17T18:40:32Z
No, I'm saying that since the lambda function is bound at compile time, this isn't a bug. It's an intentional design tradeoff. It **can't** be fixed unless the lambda function is bound at runtime instead, which would prevent it from being inlined, prevent implicit instantiation of the lambda function if it's a template, etc.
Comment #6 by andrei — 2010-08-17T19:58:25Z
I agree that the initial code shouldn't work. This code should:
import std.algorithm: map;
void main() {
auto r1 = map!q{a+1}([1, 2, 3]);
auto r2 = map!q{a+2}([1, 2, 3]);
auto a = array(chain(r1, r2));
}
Comment #7 by bearophile_hugs — 2010-08-18T03:23:38Z
Given the way templates work in D, the original code can't work, but I'd like to receive the error line number here.
This problem is a good example to show the difference between a structural type system and a nominative one.