diff options
Diffstat (limited to 'libphobos/src/std/functional.d')
-rw-r--r-- | libphobos/src/std/functional.d | 59 |
1 files changed, 50 insertions, 9 deletions
diff --git a/libphobos/src/std/functional.d b/libphobos/src/std/functional.d index b251e4006ec..bc8d368e970 100644 --- a/libphobos/src/std/functional.d +++ b/libphobos/src/std/functional.d @@ -707,19 +707,43 @@ template partial(alias fun, alias arg) { static assert(false, "Cannot apply partial to a non-callable '" ~ fun.stringof ~ "'."); } - else // Assume fun is callable and uniquely defined. + else { - static if (Parameters!fun.length == 0) + import std.meta : Filter; + + static if (__traits(compiles, __traits(getOverloads, + __traits(parent, fun), __traits(identifier, fun)))) + alias overloads = __traits(getOverloads, __traits(parent, fun), + __traits(identifier, fun)); + else + alias overloads = AliasSeq!(fun); + + enum isCallableWithArg(alias fun) = Parameters!fun.length > 0 && + is(typeof(arg) : Parameters!fun[0]); + alias candidates = Filter!(isCallableWithArg, overloads); + + static if (overloads.length == 1 && Parameters!fun.length == 0) { static assert(0, "Cannot partially apply '" ~ fun.stringof ~ "'." ~ "'" ~ fun.stringof ~ "' has 0 arguments."); } - else static if (!is(typeof(arg) : Parameters!fun[0])) + else static if (candidates.length == 0) { + import std.meta : NoDuplicates, staticMap; + + enum hasParameters(alias fun) = Parameters!fun.length > 0; + alias firstParameter(alias fun) = Parameters!fun[0]; + alias firstParameters = NoDuplicates!( + staticMap!(firstParameter, Filter!(hasParameters, overloads))); + string errorMsg() { - string msg = "Argument mismatch for '" ~ fun.stringof ~ "': expected " ~ - Parameters!fun[0].stringof ~ ", but got " ~ typeof(arg).stringof ~ "."; + string msg = "Argument mismatch for '" ~ fun.stringof ~ + "': expected " ~ firstParameters[0].stringof; + static foreach (firstParam; firstParameters[1 .. $]) + msg ~= " or " ~ firstParam.stringof; + msg ~= ", but got " ~ typeof(arg).stringof ~ "."; + return msg; } static assert(0, errorMsg()); @@ -727,10 +751,11 @@ template partial(alias fun, alias arg) else { import std.traits : ReturnType; - ReturnType!fun partial(Parameters!fun[1..$] args2) - { - return fun(arg, args2); - } + static foreach (candidate; candidates) + ReturnType!candidate partial(Parameters!candidate[1..$] args2) + { + return candidate(arg, args2); + } } } } @@ -746,6 +771,22 @@ template partial(alias fun, alias arg) // functions without committing to a particular type of the function. } +// https://issues.dlang.org/show_bug.cgi?id=21457 +/// +@safe unittest +{ + // Overloads are resolved when the partially applied function is called + // with the remaining arguments. + struct S + { + static char fun(int i, string s) { return s[i]; } + static int fun(int a, int b) { return a * b; } + } + alias fun3 = partial!(S.fun, 3); + assert(fun3("hello") == 'l'); + assert(fun3(10) == 30); +} + // tests for partially evaluating callables @safe unittest { |