LCOV - code coverage report
Current view: top level - gcc/rust/typecheck - rust-hir-dot-operator.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 91.9 % 295 271
Test Date: 2026-10-03 16:17:38 Functions: 100.0 % 14 14
Legend: Lines:     hit not hit

            Line data    Source code
       1              : // Copyright (C) 2020-2026 Free Software Foundation, Inc.
       2              : 
       3              : // This file is part of GCC.
       4              : 
       5              : // GCC is free software; you can redistribute it and/or modify it under
       6              : // the terms of the GNU General Public License as published by the Free
       7              : // Software Foundation; either version 3, or (at your option) any later
       8              : // version.
       9              : 
      10              : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      11              : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12              : // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      13              : // for more details.
      14              : 
      15              : // You should have received a copy of the GNU General Public License
      16              : // along with GCC; see the file COPYING3.  If not see
      17              : // <http://www.gnu.org/licenses/>.
      18              : 
      19              : #include "rust-hir-dot-operator.h"
      20              : #include "rust-hir-path-probe.h"
      21              : #include "rust-hir-trait-resolve.h"
      22              : #include "rust-hir-type-check-item.h"
      23              : #include "rust-type-util.h"
      24              : #include "rust-coercion.h"
      25              : 
      26              : namespace Rust {
      27              : namespace Resolver {
      28              : 
      29         6397 : MethodResolver::MethodResolver (bool autoderef_flag,
      30              :                                 const HIR::PathIdentSegment &segment_name,
      31              :                                 const HIR::Trait *specified_trait)
      32         6397 :   : AutoderefCycle (autoderef_flag), segment_name (segment_name),
      33         6397 :     specified_trait (specified_trait), result ()
      34         6397 : {}
      35              : 
      36              : std::set<MethodCandidate>
      37         6397 : MethodResolver::Probe (TyTy::BaseType *receiver,
      38              :                        const HIR::PathIdentSegment &segment_name,
      39              :                        bool autoderef_flag, const HIR::Trait *specified_trait)
      40              : {
      41         6397 :   MethodResolver resolver (autoderef_flag, segment_name, specified_trait);
      42         6397 :   resolver.cycle (receiver);
      43         6397 :   return resolver.result;
      44         6397 : }
      45              : 
      46              : std::set<MethodCandidate>
      47         3178 : MethodResolver::Select (std::set<MethodCandidate> &candidates,
      48              :                         TyTy::BaseType *receiver,
      49              :                         std::vector<TyTy::BaseType *> arguments,
      50              :                         TyTy::BaseType *result_type)
      51              : {
      52         3178 :   std::set<MethodCandidate> selected;
      53         5142 :   for (auto &candidate : candidates)
      54              :     {
      55         1964 :       TyTy::BaseType *candidate_type = candidate.candidate.ty;
      56         1964 :       rust_assert (candidate_type->get_kind () == TyTy::TypeKind::FNDEF);
      57         1964 :       if (candidate_type == nullptr
      58         1964 :           || candidate_type->get_kind () != TyTy::TypeKind::FNDEF)
      59            0 :         continue;
      60         1964 :       TyTy::FnType &fn = *static_cast<TyTy::FnType *> (candidate_type);
      61              : 
      62              :       // match the number of arguments
      63         1964 :       if (fn.num_params () != (arguments.size () + 1))
      64            0 :         continue;
      65              : 
      66              :       // match the arguments
      67         3497 :       bool failed = false;
      68         3497 :       for (size_t i = 0; i < arguments.size (); i++)
      69              :         {
      70         1630 :           TyTy::BaseType *arg = arguments.at (i);
      71         1630 :           TyTy::BaseType *param = fn.get_params ().at (i + 1).get_type ();
      72         1630 :           TyTy::BaseType *coerced
      73         1630 :             = try_coercion (0, TyTy::TyWithLocation (param),
      74         1630 :                             TyTy::TyWithLocation (arg), UNDEF_LOCATION);
      75         1630 :           if (coerced->get_kind () == TyTy::TypeKind::ERROR)
      76              :             {
      77              :               failed = true;
      78              :               break;
      79              :             }
      80              :         }
      81              : 
      82         1964 :       if (!failed && result_type != nullptr)
      83              :         {
      84           96 :           TyTy::BaseType *return_type = fn.get_return_type ();
      85           96 :           rust_debug ("method candidate output check fn=%s expected=%s "
      86              :                       "return=%s",
      87              :                       fn.debug_str ().c_str (),
      88              :                       result_type->debug_str ().c_str (),
      89              :                       return_type->debug_str ().c_str ());
      90           96 :           failed = !types_compatable (TyTy::TyWithLocation (result_type),
      91           96 :                                       TyTy::TyWithLocation (return_type),
      92              :                                       UNDEF_LOCATION, false /* emit_errors */);
      93           96 :           rust_debug ("method candidate output check result=%s",
      94              :                       failed ? "rejected" : "accepted");
      95              :         }
      96              : 
      97         1964 :       if (!failed)
      98         1786 :         selected.insert (candidate);
      99              :     }
     100              : 
     101         3178 :   return selected;
     102              : }
     103              : 
     104              : void
     105         6639 : MethodResolver::try_hook (const TyTy::BaseType &r)
     106              : {
     107         6639 :   rust_debug ("MethodResolver::try_hook get_predicate_items: [%s]",
     108              :               r.debug_str ().c_str ());
     109         6639 :   const auto &specified_bounds = r.get_specified_bounds ();
     110         6639 :   predicate_items = get_predicate_items (segment_name, r, specified_bounds);
     111              : 
     112         6639 :   if (predicate_items.size () > 0)
     113              :     return;
     114              : 
     115         6343 :   if (r.get_kind () == TyTy::TypeKind::REF)
     116              :     {
     117         3044 :       const auto &ref = static_cast<const TyTy::ReferenceType &> (r);
     118         3044 :       const auto &element = ref.get_var_element_type ();
     119         3044 :       const auto &element_ty = *element.get_tyty ();
     120         3044 :       const auto &specified_bounds = element_ty.get_specified_bounds ();
     121         3044 :       predicate_items
     122         3044 :         = get_predicate_items (segment_name, element_ty, specified_bounds);
     123              :     }
     124         3299 :   else if (auto inner
     125         3299 :            = TyTy::try_get_box_inner_type (const_cast<TyTy::BaseType *> (&r)))
     126              :     {
     127            7 :       const auto &specified_bounds = (*inner)->get_specified_bounds ();
     128            7 :       predicate_items
     129            7 :         = get_predicate_items (segment_name, **inner, specified_bounds);
     130              :     }
     131              : }
     132              : 
     133              : std::vector<MethodResolver::impl_item_candidate>
     134         3213 : MethodResolver::assemble_inherent_impl_candidates (
     135              :   const TyTy::BaseType &receiver)
     136              : {
     137         3213 :   std::vector<impl_item_candidate> inherent_impl_fns;
     138         3213 :   const TyTy::BaseType *raw = receiver.destructure ();
     139         3213 :   bool receiver_is_raw_ptr = raw->get_kind () == TyTy::TypeKind::POINTER;
     140         3213 :   bool receiver_is_ref = raw->get_kind () == TyTy::TypeKind::REF;
     141              : 
     142              :   // Assemble inherent impl items (non-trait impl blocks).
     143         3213 :   mappings.iterate_inherent_impl_items (
     144         3213 :     segment_name.to_string (),
     145         3213 :     [&] (HIR::ImplItem *item, HIR::ImplBlock *impl) mutable -> bool {
     146         7188 :       HIR::Function *func = static_cast<HIR::Function *> (item);
     147              : 
     148         7188 :       TyTy::BaseType *impl_self = TypeCheckItem::ResolveImplBlockSelf (*impl);
     149              : 
     150         7188 :       if (impl_self == nullptr
     151         7188 :           || impl_self->get_kind () == TyTy::TypeKind::ERROR)
     152              :         return true;
     153              : 
     154         7188 :       if (receiver.get_kind () == TyTy::TypeKind::ADT
     155         7188 :           && impl_self->get_kind () == TyTy::TypeKind::ADT)
     156              :         {
     157          335 :           const auto &receiver_adt
     158              :             = static_cast<const TyTy::ADTType &> (receiver);
     159          335 :           const auto &impl_adt
     160              :             = static_cast<const TyTy::ADTType &> (*impl_self);
     161          640 :           if (receiver_adt.get_id () != impl_adt.get_id ())
     162           30 :             return true;
     163              :         }
     164              : 
     165              :       // see:
     166              :       // https://gcc-rust.zulipchat.com/#narrow/stream/266897-general/topic/Method.20Resolution/near/338646280
     167              :       // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/method/probe.rs#L650-L660
     168         7158 :       bool impl_self_is_ptr = impl_self->get_kind () == TyTy::TypeKind::POINTER;
     169         7158 :       bool impl_self_is_ref = impl_self->get_kind () == TyTy::TypeKind::REF;
     170         7158 :       if (receiver_is_raw_ptr && impl_self_is_ptr)
     171              :         {
     172          573 :           const TyTy::PointerType &sptr
     173              :             = *static_cast<const TyTy::PointerType *> (impl_self);
     174          573 :           const TyTy::PointerType &ptr
     175          573 :             = *static_cast<const TyTy::PointerType *> (raw);
     176              : 
     177              :           // we could do this via lang-item assemblies if we refactor this
     178          573 :           bool mut_match = sptr.mutability () == ptr.mutability ();
     179          573 :           if (!mut_match)
     180              :             return true;
     181              :         }
     182         6585 :       else if (receiver_is_ref && impl_self_is_ref)
     183              :         {
     184            0 :           const TyTy::ReferenceType &sptr
     185              :             = *static_cast<const TyTy::ReferenceType *> (impl_self);
     186            0 :           const TyTy::ReferenceType &ptr
     187            0 :             = *static_cast<const TyTy::ReferenceType *> (raw);
     188              : 
     189              :           // we could do this via lang-item assemblies if we refactor this
     190            0 :           bool mut_match = sptr.mutability () == ptr.mutability ();
     191            0 :           if (!mut_match)
     192              :             return true;
     193              :         }
     194              : 
     195         7017 :       TyTy::BaseType *ty = nullptr;
     196         7017 :       if (!query_type (func->get_mappings ().get_hirid (), &ty))
     197              :         return true;
     198         7017 :       if (ty == nullptr || ty->get_kind () == TyTy::TypeKind::ERROR)
     199              :         return true;
     200         7017 :       if (ty->get_kind () != TyTy::TypeKind::FNDEF)
     201              :         return true;
     202              : 
     203         7017 :       TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty);
     204         7017 :       inherent_impl_fns.emplace_back (func, impl, fnty);
     205         7017 :       return true;
     206              :     });
     207              : 
     208         3213 :   return inherent_impl_fns;
     209              : }
     210              : 
     211              : void
     212         4986 : MethodResolver::assemble_trait_impl_candidates (
     213              :   const TyTy::BaseType &receiver,
     214              :   std::vector<impl_item_candidate> &impl_candidates,
     215              :   std::vector<trait_item_candidate> &trait_candidates)
     216              : {
     217         4986 :   const TyTy::BaseType *raw = receiver.destructure ();
     218         4986 :   bool receiver_is_raw_ptr = raw->get_kind () == TyTy::TypeKind::POINTER;
     219         4986 :   bool receiver_is_ref = raw->get_kind () == TyTy::TypeKind::REF;
     220              : 
     221        22080 :   auto process_impl = [&] (HirId id, HIR::ImplBlock *impl) mutable -> bool {
     222        17094 :     bool is_trait_impl = impl->has_trait_ref ();
     223        17094 :     if (!is_trait_impl)
     224              :       return true;
     225              : 
     226              :     // look for impl implementation else lookup the associated trait item
     227        32869 :     for (auto &impl_item : impl->get_impl_items ())
     228              :       {
     229        31087 :         bool is_fn = impl_item->get_impl_item_type ()
     230        31087 :                      == HIR::ImplItem::ImplItemType::FUNCTION;
     231        31087 :         if (!is_fn)
     232        15775 :           continue;
     233              : 
     234        22143 :         HIR::Function *func = static_cast<HIR::Function *> (impl_item.get ());
     235        22143 :         if (!func->is_method ())
     236            0 :           continue;
     237              : 
     238        22143 :         bool name_matches = func->get_function_name ().as_string ().compare (
     239        44286 :                               segment_name.to_string ())
     240        22143 :                             == 0;
     241        22143 :         if (!name_matches)
     242         6563 :           continue;
     243              : 
     244        15580 :         TyTy::BaseType *impl_self = TypeCheckItem::ResolveImplBlockSelf (*impl);
     245              : 
     246        15580 :         if (impl_self == nullptr
     247        15580 :             || impl_self->get_kind () == TyTy::TypeKind::ERROR)
     248            0 :           continue;
     249              : 
     250        15580 :         if (receiver.get_kind () == TyTy::TypeKind::ADT
     251        15580 :             && impl_self->get_kind () == TyTy::TypeKind::ADT)
     252              :           {
     253          545 :             const auto &receiver_adt
     254              :               = static_cast<const TyTy::ADTType &> (receiver);
     255          545 :             const auto &impl_adt
     256              :               = static_cast<const TyTy::ADTType &> (*impl_self);
     257          943 :             if (receiver_adt.get_id () != impl_adt.get_id ())
     258          147 :               continue;
     259              :           }
     260              : 
     261              :         // see:
     262              :         // https://gcc-rust.zulipchat.com/#narrow/stream/266897-general/topic/Method.20Resolution/near/338646280
     263              :         // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/method/probe.rs#L650-L660
     264        15433 :         bool impl_self_is_ptr
     265        15433 :           = impl_self->get_kind () == TyTy::TypeKind::POINTER;
     266        15433 :         bool impl_self_is_ref = impl_self->get_kind () == TyTy::TypeKind::REF;
     267        15433 :         if (receiver_is_raw_ptr && impl_self_is_ptr)
     268              :           {
     269            0 :             const TyTy::PointerType &sptr
     270              :               = *static_cast<const TyTy::PointerType *> (impl_self);
     271            0 :             const TyTy::PointerType &ptr
     272            0 :               = *static_cast<const TyTy::PointerType *> (raw);
     273              : 
     274              :             // we could do this via lang-item assemblies if we refactor this
     275            0 :             bool mut_match = sptr.mutability () == ptr.mutability ();
     276            0 :             if (!mut_match)
     277            0 :               continue;
     278              :           }
     279        15433 :         else if (receiver_is_ref && impl_self_is_ref)
     280              :           {
     281          291 :             const TyTy::ReferenceType &sptr
     282              :               = *static_cast<const TyTy::ReferenceType *> (impl_self);
     283          291 :             const TyTy::ReferenceType &ptr
     284          291 :               = *static_cast<const TyTy::ReferenceType *> (raw);
     285              : 
     286              :             // we could do this via lang-item assemblies if we refactor this
     287          291 :             bool mut_match = sptr.mutability () == ptr.mutability ();
     288          291 :             if (!mut_match)
     289          121 :               continue;
     290              :           }
     291              : 
     292        15312 :         TyTy::BaseType *ty = nullptr;
     293        15312 :         if (!query_type (func->get_mappings ().get_hirid (), &ty))
     294            0 :           continue;
     295        15312 :         if (ty == nullptr || ty->get_kind () == TyTy::TypeKind::ERROR)
     296            0 :           continue;
     297        15312 :         if (ty->get_kind () != TyTy::TypeKind::FNDEF)
     298            0 :           continue;
     299              : 
     300        15312 :         TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty);
     301              : 
     302        15312 :         impl_candidates.emplace_back (func, impl, fnty);
     303        15312 :         return true;
     304              :       }
     305              : 
     306         1782 :     TraitReference *trait_ref = TraitResolver::Resolve (impl->get_trait_ref ());
     307         1782 :     rust_assert (!trait_ref->is_error ());
     308              : 
     309         1782 :     auto item_ref
     310         3564 :       = trait_ref->lookup_trait_item (segment_name.to_string (),
     311         1782 :                                       TraitItemReference::TraitItemType::FN);
     312         1782 :     if (item_ref->is_error ())
     313              :       return true;
     314              : 
     315         1446 :     const HIR::Trait *trait = trait_ref->get_hir_trait_ref ();
     316         1446 :     HIR::TraitItem *item = item_ref->get_hir_trait_item ();
     317         1446 :     if (item->get_item_kind () != HIR::TraitItem::TraitItemKind::FUNC)
     318              :       return true;
     319              : 
     320         1446 :     HIR::TraitItemFunc *func = static_cast<HIR::TraitItemFunc *> (item);
     321         1446 :     if (!func->get_decl ().is_method ())
     322              :       return true;
     323              : 
     324         1446 :     TyTy::BaseType *ty = item_ref->get_tyty ();
     325         1446 :     if (ty == nullptr || ty->get_kind () != TyTy::TypeKind::FNDEF)
     326              :       return true;
     327         1446 :     TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty);
     328              : 
     329         1446 :     trait_candidates.emplace_back (func, trait, fnty, trait_ref, item_ref);
     330              : 
     331         1446 :     return true;
     332         4986 :   };
     333              : 
     334         4986 :   if (specified_trait == nullptr)
     335         3106 :     mappings.iterate_trait_impl_blocks_for_item (segment_name.to_string (),
     336         3106 :                                                  process_impl);
     337              :   else
     338         3433 :     mappings.iterate_trait_impl_blocks (
     339         6866 :       specified_trait->get_mappings ().get_defid (), process_impl);
     340         4986 : }
     341              : 
     342              : bool
     343         8126 : MethodResolver::try_select_predicate_candidates (TyTy::BaseType &receiver)
     344              : {
     345         8126 :   bool found_possible_candidate = false;
     346         9608 :   for (const auto &predicate : predicate_items)
     347              :     {
     348         1482 :       if (specified_trait != nullptr)
     349              :         {
     350          284 :           const TraitReference *parent = predicate.lookup.get_parent ()->get ();
     351          284 :           if (parent->get_mappings ().get_defid ()
     352          568 :               != specified_trait->get_mappings ().get_defid ())
     353            0 :             continue;
     354              :         }
     355              : 
     356         1482 :       const TyTy::FnType *fn = predicate.fntype;
     357         2964 :       if (!fn->is_method ())
     358            0 :         continue;
     359              : 
     360         1482 :       TyTy::BaseType *fn_self = fn->get_self_type ();
     361         1482 :       rust_debug ("dot-operator predicate fn_self={%s} can_eq receiver={%s}",
     362              :                   fn_self->debug_str ().c_str (),
     363              :                   receiver.debug_str ().c_str ());
     364              : 
     365         1482 :       auto res
     366              :         = TypeCoercionRules::TryCoerce (&receiver, fn_self, UNDEF_LOCATION,
     367         1482 :                                         false /*allow-autoderef*/);
     368         1482 :       bool ok = !res.is_error ();
     369         1482 :       if (ok)
     370              :         {
     371         1337 :           std::vector<Adjustment> adjs = append_adjustments (res.adjustments);
     372         1337 :           const TraitReference *trait_ref
     373         1337 :             = predicate.lookup.get_parent ()->get ();
     374         1337 :           const TraitItemReference *trait_item
     375         1337 :             = predicate.lookup.get_raw_item ();
     376              : 
     377         1337 :           PathProbeCandidate::TraitItemCandidate c{trait_ref, trait_item,
     378         1337 :                                                    nullptr};
     379         1337 :           auto try_result = MethodCandidate{
     380              :             PathProbeCandidate (PathProbeCandidate::CandidateType::TRAIT_FUNC,
     381              :                                 fn->clone (), trait_item->get_locus (), c),
     382         1337 :             adjs};
     383         1337 :           result.insert (std::move (try_result));
     384         1337 :           found_possible_candidate = true;
     385         1337 :         }
     386         1482 :     }
     387         8126 :   return found_possible_candidate;
     388              : }
     389              : 
     390              : bool
     391         8199 : MethodResolver::try_select_inherent_impl_candidates (
     392              :   TyTy::BaseType &receiver, const std::vector<impl_item_candidate> &candidates,
     393              :   bool trait_impl_blocks_only)
     394              : {
     395         8199 :   bool found_possible_candidate = false;
     396        30528 :   for (auto &impl_item : candidates)
     397              :     {
     398        22329 :       bool is_trait_impl_block = impl_item.impl_block->has_trait_ref ();
     399        22329 :       if (trait_impl_blocks_only && !is_trait_impl_block)
     400            0 :         continue;
     401        22329 :       if (!trait_impl_blocks_only && is_trait_impl_block)
     402            0 :         continue;
     403              : 
     404        22329 :       TyTy::FnType *fn = impl_item.ty;
     405        44658 :       if (!fn->is_method ())
     406            0 :         continue;
     407              : 
     408        22329 :       TyTy::BaseType *fn_self = fn->get_self_type ();
     409              : 
     410         7017 :       const char *debug_prefix
     411        22329 :         = trait_impl_blocks_only ? "trait_impl_item" : "impl_item";
     412        22329 :       rust_debug ("dot-operator %s fn_self={%s} can_eq receiver={%s}",
     413              :                   debug_prefix, fn_self->debug_str ().c_str (),
     414              :                   receiver.debug_str ().c_str ());
     415              : 
     416        22329 :       auto res
     417              :         = TypeCoercionRules::TryCoerce (&receiver, fn_self, UNDEF_LOCATION,
     418        22329 :                                         false /*allow-autoderef*/);
     419        22329 :       bool ok = !res.is_error ();
     420        22329 :       if (ok)
     421              :         {
     422         5220 :           std::vector<Adjustment> adjs = append_adjustments (res.adjustments);
     423         5220 :           PathProbeCandidate::ImplItemCandidate c{impl_item.item,
     424         5220 :                                                   impl_item.impl_block};
     425         5220 :           auto try_result = MethodCandidate{
     426              :             PathProbeCandidate (PathProbeCandidate::CandidateType::IMPL_FUNC,
     427         5220 :                                 fn, impl_item.item->get_locus (), c),
     428         5220 :             adjs};
     429         5220 :           result.insert (std::move (try_result));
     430         5220 :           found_possible_candidate = true;
     431         5220 :         }
     432        22329 :     }
     433         8199 :   return found_possible_candidate;
     434              : }
     435              : 
     436              : bool
     437         1821 : MethodResolver::try_select_trait_impl_candidates (
     438              :   TyTy::BaseType &receiver, const std::vector<trait_item_candidate> &candidates)
     439              : {
     440         1821 :   bool found_possible_candidate = false;
     441         2196 :   for (auto trait_item : candidates)
     442              :     {
     443          375 :       TyTy::FnType *fn = trait_item.ty;
     444          750 :       if (!fn->is_method ())
     445            0 :         continue;
     446              : 
     447          375 :       TyTy::BaseType *fn_self = fn->get_self_type ();
     448          375 :       rust_debug ("dot-operator trait_item fn_self={%s} can_eq receiver={%s}",
     449              :                   fn_self->debug_str ().c_str (),
     450              :                   receiver.debug_str ().c_str ());
     451              : 
     452          375 :       auto res
     453              :         = TypeCoercionRules::TryCoerce (&receiver, fn_self, UNDEF_LOCATION,
     454          375 :                                         false /*allow-autoderef*/);
     455          375 :       bool ok = !res.is_error ();
     456          375 :       if (ok)
     457              :         {
     458          223 :           std::vector<Adjustment> adjs = append_adjustments (res.adjustments);
     459          223 :           PathProbeCandidate::TraitItemCandidate c{trait_item.reference,
     460              :                                                    trait_item.item_ref,
     461          223 :                                                    nullptr};
     462          223 :           auto try_result = MethodCandidate{
     463              :             PathProbeCandidate (PathProbeCandidate::CandidateType::TRAIT_FUNC,
     464          223 :                                 fn, trait_item.item->get_locus (), c),
     465          223 :             adjs};
     466          223 :           result.insert (std::move (try_result));
     467          223 :           found_possible_candidate = true;
     468          223 :         }
     469          375 :     }
     470         1821 :   return found_possible_candidate;
     471              : }
     472              : 
     473              : bool
     474         8126 : MethodResolver::select (TyTy::BaseType &receiver)
     475              : {
     476         8126 :   rust_debug ("MethodResolver::select reciever=[%s] path=[%s]",
     477              :               receiver.debug_str ().c_str (),
     478              :               segment_name.to_string ().c_str ());
     479              : 
     480              :   // Predicate candidates have the highest priority.  Try them before
     481              :   // assembling impl candidates, which can trigger expensive trait resolution.
     482         8126 :   if (try_select_predicate_candidates (receiver))
     483              :     return true;
     484              : 
     485              :   // A receiver that is still a bare unresolved generic type parameter can only
     486              :   // ever satisfy a method through its own trait bounds
     487         6789 :   if (receiver.destructure ()->get_kind () == TyTy::TypeKind::PARAM)
     488              :     return false;
     489              : 
     490              :   // Assemble candidates
     491         6646 :   std::vector<impl_item_candidate> inherent_impl_fns;
     492         6646 :   if (specified_trait == nullptr)
     493              :     {
     494         3213 :       inherent_impl_fns = assemble_inherent_impl_candidates (receiver);
     495         3213 :       if (try_select_inherent_impl_candidates (receiver, inherent_impl_fns,
     496              :                                                false))
     497              :         return true;
     498              :     }
     499              : 
     500         4986 :   std::vector<impl_item_candidate> trait_impl_fns;
     501         4986 :   std::vector<trait_item_candidate> trait_fns;
     502         4986 :   assemble_trait_impl_candidates (receiver, trait_impl_fns, trait_fns);
     503              : 
     504              :   // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/method/probe.rs#L580-L694
     505              : 
     506         4986 :   rust_debug ("inherent_impl_fns found {%lu}, trait_fns found {%lu}, "
     507              :               "predicate_items found {%lu}",
     508              :               (unsigned long) inherent_impl_fns.size (),
     509              :               (unsigned long) trait_fns.size (),
     510              :               (unsigned long) predicate_items.size ());
     511              : 
     512              :   // Try selection in the priority order defined by Rust's method resolution:
     513              : 
     514              :   // 1. Try inherent impl functions from trait impl blocks
     515         4986 :   if (try_select_inherent_impl_candidates (receiver, trait_impl_fns, true))
     516              :     return true;
     517              : 
     518              :   // 2. Try trait functions (lowest priority)
     519         1821 :   return try_select_trait_impl_candidates (receiver, trait_fns);
     520        11632 : }
     521              : 
     522              : std::vector<MethodResolver::predicate_candidate>
     523         9690 : MethodResolver::get_predicate_items (
     524              :   const HIR::PathIdentSegment &segment_name, const TyTy::BaseType &receiver,
     525              :   const std::vector<TyTy::TypeBoundPredicate> &specified_bounds)
     526              : {
     527         9690 :   std::vector<predicate_candidate> predicate_items;
     528        12165 :   for (auto &bound : specified_bounds)
     529              :     {
     530         2475 :       tl::optional<TyTy::TypeBoundPredicateItem> lookup
     531         2475 :         = bound.lookup_associated_item (segment_name.to_string ());
     532         2475 :       if (!lookup.has_value ())
     533         1133 :         continue;
     534              : 
     535         1342 :       TyTy::BaseType *ty = lookup->get_tyty_for_receiver (&receiver);
     536         1342 :       if (ty->get_kind () == TyTy::TypeKind::FNDEF)
     537              :         {
     538         1342 :           TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty);
     539         4022 :           if (fnty->is_method ())
     540         1338 :             predicate_items.emplace_back (lookup.value (), fnty);
     541              :         }
     542         2475 :     }
     543              : 
     544         9690 :   return predicate_items;
     545              : }
     546              : 
     547              : std::vector<Adjustment>
     548         6780 : MethodResolver::append_adjustments (const std::vector<Adjustment> &adjs) const
     549              : {
     550         6780 :   std::vector<Adjustment> combined;
     551         6780 :   combined.reserve (adjustments.size () + adjs.size ());
     552              : 
     553         7672 :   for (const auto &a : adjustments)
     554          892 :     combined.push_back (a);
     555         6871 :   for (const auto &a : adjs)
     556           91 :     combined.push_back (a);
     557              : 
     558         6780 :   return combined;
     559              : }
     560              : 
     561              : } // namespace Resolver
     562              : } // namespace Rust
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.