From 55e858010b9ba53c27475d9ce6f864a84d28fa81 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Sat, 14 Jul 2018 18:30:28 +0200 Subject: Resolve function overload via the argument reversal to untyped --- build2/function.cxx | 84 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 62 insertions(+), 22 deletions(-) (limited to 'build2/function.cxx') diff --git a/build2/function.cxx b/build2/function.cxx index 4367185..0b432d3 100644 --- a/build2/function.cxx +++ b/build2/function.cxx @@ -118,22 +118,21 @@ namespace build2 // Overload resolution. // - // Ours is pretty simple: if all the arguments match exactly, then we have - // a perfect match. Otherwise, if any argument matches via the derived-to- - // base conversion, then we have an imperfect match. More than one perfect - // or imperfect match is ambiguous (i.e., we don't try to rank imperfect - // matches). + // Ours is pretty simple: we sort all the overloads into three ranks: // - size_t count (args.size ()); - auto ip (map_.equal_range (name)); - - // First look for a perfect match, then for imperfect. We do it this way - // to make sure we always stay small in the successful case. + // 0 -- all the arguments match exactly (perfect match) + // 1 -- one or more arguments match via the derived-to-base conversion + // 2 -- one or more arguments match via the reversal to untyped // - small_vector r; + // More than one match of the same rank is ambiguous. + // + auto ip (map_.equal_range (name)); - for (bool perf (true);; perf = false) + size_t rank (~0); + small_vector ovls; { + size_t count (args.size ()); + for (auto it (ip.first); it != ip.second; ++it) { const function_overload& f (it->second); @@ -145,6 +144,7 @@ namespace build2 // Argument types match. // + size_t r (0); { size_t i (0), n (min (count, f.arg_types.size ())); for (; i != n; ++i) @@ -158,29 +158,50 @@ namespace build2 if (at == ft) // Types match perfectly. continue; - if (!perf && at != nullptr && ft != nullptr) + if (at != nullptr && ft != nullptr) { while ((at = at->base_type) != nullptr && at != ft) ; if (at != nullptr) // Types match via derived-to-base. + { + if (r < 1) + r = 1; continue; + } } - break; + if (ft == nullptr) // Types match via reversal to untyped. + { + if (r < 2) + r = 2; + continue; + } + + break; // No match. } if (i != n) - continue; + continue; // No match. } - r.push_back (&f); // Continue looking to detect ambiguities. - } + // Better or just as good a match? + // + if (r <= rank) + { + if (r < rank) // Better. + { + rank = r; + ovls.clear (); + } + + ovls.push_back (&f); + } - if (!r.empty () || !perf) - break; + // Continue looking to detect ambiguities. + } } - switch (r.size ()) + switch (ovls.size ()) { case 1: { @@ -197,7 +218,26 @@ namespace build2 } })); - auto f (r.back ()); + auto f (ovls.back ()); + + // If one or more arguments match via the reversal to untyped (rank 2), + // then we need to go over the overload's arguments one more time an + // untypify() those that we need to reverse. + // + if (rank == 2) + { + size_t n (args.size ()); + assert (n <= f->arg_types.size ()); + + for (size_t i (0); i != n; ++i) + { + if (f->arg_types[i] && + *f->arg_types[i] == nullptr && + args[i].type != nullptr) + untypify (args[i]); + } + } + return make_pair (f->impl (base, move (args), *f), true); } case 0: @@ -246,7 +286,7 @@ namespace build2 diag_record dr; dr << fail (loc) << "ambiguous call to "; print_call (dr.os); - for (auto f: r) + for (auto f: ovls) dr << info << "candidate: " << *f; dr << endf; -- cgit v1.1