Bug 6714 – [tdpl] Type inference for parameters of function and delegate literals
Status
RESOLVED
Resolution
FIXED
Severity
enhancement
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
Other
OS
All
Creation time
2011-09-22T07:31:00Z
Last change time
2011-12-31T12:24:37Z
Keywords
patch, rejects-valid, spec
Assigned to
nobody
Creator
andrei
Comments
Comment #0 by andrei — 2011-09-22T07:31:43Z
Consider:
void foo (int function (int, int) a){}
void bar (int delegate (int, int) a){}
void main ()
{
foo((a, b) { return a +b;});
bar((a, b) { return a +b;});
}
Neither call works. The literal does not convert to the function or the delegate type.
Additionally (this might have been reported), a function type should convert automatically to a delegate type with the same arguments and return type. Walter has expressed doubts about that. The doubts are unfounded.
(In reply to comment #0)
> Consider:
>
>
> void foo (int function (int, int) a){}
> void bar (int delegate (int, int) a){}
>
> void main ()
> {
> foo((a, b) { return a +b;});
> bar((a, b) { return a +b;});
> }
>
> Neither call works. The literal does not convert to the function or the
> delegate type.
This works though:
bar((int a, int b) { return a + b;});
Is that what you meant? If it is, then this is a duplicate of 3235.
Or are argument types supposed to be deduced? If so, that's a major, complicated feature and difficult to implement, I think it requires an extra level of argument matching. It would need to be considered very carefully.
Eg, which of these calls are ambiguous?
void bar ( double delegate(int, int) a ) {}
void bar ( int delegate (int, int) a ){}
bar( (a, b) { return 1.0; } );
bar( (a, b) { return 1.0f; } );
bar( (a, b) { return a; } );
Comment #3 by andrei — 2011-12-24T09:32:58Z
(In reply to comment #2)
> (In reply to comment #0)
> > Consider:
> >
> >
> > void foo (int function (int, int) a){}
> > void bar (int delegate (int, int) a){}
> >
> > void main ()
> > {
> > foo((a, b) { return a +b;});
> > bar((a, b) { return a +b;});
> > }
> >
> > Neither call works. The literal does not convert to the function or the
> > delegate type.
>
> This works though:
> bar((int a, int b) { return a + b;});
> Is that what you meant? If it is, then this is a duplicate of 3235.
>
> Or are argument types supposed to be deduced? If so, that's a major,
> complicated feature and difficult to implement, I think it requires an extra
> level of argument matching.
When I discussed with Walter the matter a while ago, a possible approach was that the literal relying on deduction defines a local template function. For example, the code:
foo((a, b) { return a +b;});
would be lowered into:
static auto __lambda(T1, T2)(T1 a, T2 b) { return a + b; }
foo(__lambda);
The "static" is present because the compiler figured the lambda uses no state from the enclosing context. Built-in conversion mechanisms should take over from here on.
This also brings the issue of automatically converting a function to a delegate. Walter disagrees with that, but I disagree with the basis of his disagreement.
> It would need to be considered very carefully.
> Eg, which of these calls are ambiguous?
>
> void bar ( double delegate(int, int) a ) {}
> void bar ( int delegate (int, int) a ){}
>
> bar( (a, b) { return 1.0; } );
Works, goes to first overload.
> bar( (a, b) { return 1.0f; } );
Doesn't work, no conversion possible for either overload.
> bar( (a, b) { return a; } );
Depends on a's type.
Comment #4 by clugdbug — 2011-12-26T17:10:36Z
(In reply to comment #3)
> (In reply to comment #2)
> > (In reply to comment #0)
> > > Consider:
> > >
> > >
> > > void foo (int function (int, int) a){}
> > > void bar (int delegate (int, int) a){}
> > >
> > > void main ()
> > > {
> > > foo((a, b) { return a +b;});
> > > bar((a, b) { return a +b;});
> > > }
> > Are argument types supposed to be deduced? If so, that's a major,
> > complicated feature and difficult to implement, I think it requires an extra
> > level of argument matching.
>
> When I discussed with Walter the matter a while ago, a possible approach was
> that the literal relying on deduction defines a local template function.
Changing bug title from the original ´Function literal does not convert to "function" and "delegate" types´, since this seems to be type inference enhancement, which requires a spec change.
> For example, the code:
>
> foo((a, b) { return a +b;});
>
> would be lowered into:
>
> static auto __lambda(T1, T2)(T1 a, T2 b) { return a + b; }
> foo(__lambda);
>
> The "static" is present because the compiler figured the lambda uses no state
> from the enclosing context. Built-in conversion mechanisms should take over
> from here on.
I don't understand how this works. Where does the template get instantiated?
In the examples at the end of comment 3, it seems to be deducing the parameters of __lambda from parameters of foo. This seems very complicated.
If foo is a template function, in every existing situation, all the types of the arguments are known. Here, they aren't. For example if foo is:
void foo(T = int, R)( R function(T, T) f)
then we'd expect T1, T2 to be deduced as int (because of the default value of T). We now have enough information to instantiate __lambda, which then allows us to determine R. We can then finally instantiate foo. We're instantiating two templates at once, and they're kind of interlocked. The interlocking continues further: if the parameter deduction or template constraint of foo fails, then the instantiation of __lambda must also be discarded.
The 4-step template argument deduction process described in template.html is gone.
> This also brings the issue of automatically converting a function to a
> delegate. Walter disagrees with that, but I disagree with the basis of his
> disagreement.
Obviously this needs to be resolved.