LCOV - code coverage report
Current view: top level - gcc/rust/typecheck - rust-type-util.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 92.3 % 444 410
Test Date: 2026-10-03 16:17:38 Functions: 100.0 % 11 11
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-item.h"
      20              : #include "rust-system.h"
      21              : #include "rust-type-util.h"
      22              : #include "rust-diagnostics.h"
      23              : #include "rust-hir-map.h"
      24              : #include "rust-hir-type-check-implitem.h"
      25              : #include "rust-hir-type-check-item.h"
      26              : #include "rust-hir-type-check.h"
      27              : #include "rust-casts.h"
      28              : #include "rust-mapping-common.h"
      29              : #include "rust-rib.h"
      30              : #include "rust-unify.h"
      31              : #include "rust-coercion.h"
      32              : #include "rust-hir-type-bounds.h"
      33              : #include "rust-hir-trait-resolve.h"
      34              : #include "rust-substitution-mapper.h"
      35              : #include "rust-finalized-name-resolution-context.h"
      36              : 
      37              : namespace Rust {
      38              : namespace Resolver {
      39              : 
      40              : const size_t kNormalizeProjectionLimit = 10;
      41              : 
      42              : bool
      43       439178 : query_type (HirId reference, TyTy::BaseType **result)
      44              : {
      45       439178 :   auto &mappings = Analysis::Mappings::get ();
      46       439178 :   TypeCheckContext *context = TypeCheckContext::get ();
      47              : 
      48       439178 :   if (context->lookup_type (reference, result))
      49              :     return true;
      50              : 
      51         7995 :   if (context->query_in_progress (reference))
      52              :     return false;
      53              : 
      54         7993 :   context->insert_query (reference);
      55              : 
      56         7993 :   std::pair<HIR::Enum *, HIR::EnumItem *> enum_candidiate
      57         7993 :     = mappings.lookup_hir_enumitem (reference);
      58        15986 :   bool enum_candidiate_ok
      59         7993 :     = enum_candidiate.first != nullptr && enum_candidiate.second != nullptr;
      60         7993 :   if (enum_candidiate_ok)
      61              :     {
      62         4495 :       HIR::Enum *parent = enum_candidiate.first;
      63         4495 :       HIR::EnumItem *enum_item = enum_candidiate.second;
      64         4495 :       rust_debug_loc (enum_item->get_locus (), "resolved item {%u} to",
      65              :                       reference);
      66              : 
      67         4495 :       *result = TypeCheckItem::Resolve (*parent);
      68              : 
      69         4495 :       context->query_completed (reference);
      70         4495 :       return true;
      71              :     }
      72              : 
      73         3498 :   if (auto item = mappings.lookup_hir_item (reference))
      74              :     {
      75          935 :       rust_debug_loc (item.value ()->get_locus (), "resolved item {%u} to",
      76              :                       reference);
      77              : 
      78          935 :       DefId item_defid = item.value ()->get_mappings ().get_defid ();
      79          935 :       bool is_local = item_defid.crateNum == mappings.get_current_crate ();
      80          935 :       bool is_fn
      81          935 :         = item.value ()->get_item_kind () == HIR::Item::ItemKind::Function;
      82          935 :       bool is_const_fn = false;
      83          935 :       if (is_fn)
      84              :         {
      85          200 :           auto &fn = *static_cast<HIR::Function *> (item.value ());
      86          200 :           is_const_fn = fn.get_qualifiers ().is_const ();
      87              :         }
      88              : 
      89          200 :       bool needs_full_resolve_for_const
      90          200 :         = is_fn && context->const_context_p () && is_const_fn;
      91          935 :       if (is_fn && is_local && !needs_full_resolve_for_const)
      92              :         {
      93          179 :           HIR::Function &fn = *static_cast<HIR::Function *> (item.value ());
      94          179 :           *result = TypeCheckItem::ResolveFunctionSignature (fn);
      95          179 :         }
      96          756 :       else if (item.value ()->get_item_kind () == HIR::Item::ItemKind::Trait
      97          756 :                && is_local && !context->const_context_p ())
      98              :         {
      99          409 :           HIR::Trait &trait = *static_cast<HIR::Trait *> (item.value ());
     100          409 :           *result = TypeCheckItem::ResolveTraitSignature (trait);
     101              :         }
     102              :       else
     103          347 :         *result = TypeCheckItem::Resolve (*item.value ());
     104              : 
     105          935 :       context->query_completed (reference);
     106          935 :       return true;
     107              :     }
     108              : 
     109         2563 :   if (auto impl_item = mappings.lookup_hir_implitem (reference))
     110              :     {
     111         2043 :       auto impl_block
     112         2043 :         = mappings.lookup_hir_impl_block (impl_item->second).value ();
     113         2043 :       auto lifetime_pin = context->push_clean_lifetime_resolver (true);
     114              : 
     115         2043 :       bool failure_flag = false;
     116         2043 :       auto substitutions
     117              :         = TypeCheckItem::ResolveImplBlockSubstitutions (*impl_block,
     118         2043 :                                                         failure_flag);
     119         2043 :       if (failure_flag)
     120              :         {
     121            1 :           *result
     122            1 :             = TypeCheckItem::ResolveImplItem (*impl_block, *impl_item->first);
     123            1 :           context->query_completed (reference);
     124            1 :           return true;
     125              :         }
     126              : 
     127         2042 :       TyTy::BaseType *self = nullptr;
     128         2042 :       bool ok
     129         2042 :         = query_type (impl_block->get_type ().get_mappings ().get_hirid (),
     130              :                       &self);
     131         2042 :       if (!ok)
     132              :         {
     133            0 :           context->query_completed (reference);
     134            0 :           return false;
     135              :         }
     136              : 
     137         2042 :       tl::optional<ImplTraitFrameGuard> guard;
     138         2042 :       if (impl_block->has_trait_ref ())
     139              :         {
     140         1419 :           HIR::TypePath &ref = impl_block->get_trait_ref ();
     141         1419 :           auto trait_reference = TraitResolver::Resolve (ref);
     142         1419 :           if (trait_reference->is_error ())
     143              :             {
     144            0 :               context->query_completed (reference);
     145            0 :               return false;
     146              :             }
     147              : 
     148         1419 :           auto specified_bound = TypeCheckBase::ResolvePredicateFromBound (
     149         1419 :             ref, impl_block->get_type (), impl_block->get_polarity ());
     150              : 
     151         1419 :           std::map<DefId, AssocTypeEntry> assoc_types_by_trait_item;
     152         1419 :           std::vector<const TraitItemReference *> trait_item_refs;
     153         1419 :           TypeCheckItem::ResolveImplTraitAssociatedTypes (
     154              :             context, *impl_block, specified_bound, self, substitutions,
     155              :             assoc_types_by_trait_item, trait_item_refs);
     156              : 
     157         1419 :           ImplTraitContextFrame frame{trait_reference, self,
     158         1419 :                                       std::move (assoc_types_by_trait_item)};
     159         1419 :           guard.emplace (frame);
     160         1419 :         }
     161              : 
     162              :       // found an impl item
     163         2042 :       rust_debug_loc (impl_item->first->get_locus (),
     164              :                       "resolved impl-item {%u} to", reference);
     165              : 
     166         2042 :       DefId item_defid = impl_item->first->get_impl_mappings ().get_defid ();
     167         2042 :       bool is_local = item_defid.crateNum == mappings.get_current_crate ();
     168         2042 :       bool is_fn
     169         2042 :         = impl_item->first->get_impl_item_type () == HIR::ImplItem::FUNCTION;
     170         2042 :       bool is_const_fn = false;
     171         2042 :       if (is_fn)
     172              :         {
     173         2033 :           auto &fn = *static_cast<HIR::Function *> (impl_item->first);
     174         2033 :           is_const_fn = fn.get_qualifiers ().is_const ();
     175              :         }
     176              : 
     177         2033 :       bool needs_full_resolve_for_const
     178         2033 :         = is_fn && context->const_context_p () && is_const_fn;
     179         2042 :       if (is_fn && is_local && !needs_full_resolve_for_const)
     180              :         {
     181         2031 :           HIR::Function &fn = *static_cast<HIR::Function *> (impl_item->first);
     182         2031 :           *result = TypeCheckImplItem::ResolveFunctionSignature (
     183              :             *impl_block, fn, self, std::move (substitutions));
     184         2031 :         }
     185              :       else
     186           11 :         *result = TypeCheckImplItem::Resolve (*impl_block, *impl_item->first,
     187              :                                               self, std::move (substitutions));
     188              : 
     189         2042 :       context->query_completed (reference);
     190         2042 :       return true;
     191         2043 :     }
     192              : 
     193              :   // is it an impl_type?
     194          520 :   if (auto impl_block_by_type = mappings.lookup_impl_block_type (reference))
     195              :     {
     196              :       // found an impl item
     197          464 :       HIR::ImplBlock *impl = impl_block_by_type.value ();
     198          464 :       rust_debug_loc (impl->get_locus (), "resolved impl block type {%u} to",
     199              :                       reference);
     200              : 
     201              :       // this could be recursive to the root type
     202          464 :       if (impl->has_type ())
     203              :         {
     204          464 :           HIR::Type &ty = impl->get_type ();
     205          464 :           NodeId ref_node_id = UNKNOWN_NODEID;
     206          464 :           NodeId ast_node_id = ty.get_mappings ().get_nodeid ();
     207              : 
     208          464 :           auto &nr_ctx = Resolver2_0::FinalizedNameResolutionContext::get ();
     209              : 
     210              :           // assign the ref_node_id if we've found something
     211          464 :           nr_ctx.lookup (ast_node_id, Resolver2_0::Namespace::Types)
     212          905 :             .map ([&ref_node_id] (NodeId resolved) { ref_node_id = resolved; });
     213              : 
     214          464 :           if (ref_node_id != UNKNOWN_NODEID)
     215              :             {
     216          441 :               tl::optional<HirId> hid
     217          441 :                 = mappings.lookup_node_to_hir (ref_node_id);
     218          441 :               if (hid.has_value () && context->query_in_progress (hid.value ()))
     219              :                 {
     220            0 :                   context->query_completed (reference);
     221            0 :                   return false;
     222              :                 }
     223              :             }
     224              :         }
     225              : 
     226          464 :       *result = TypeCheckItem::ResolveImplBlockSelf (*impl);
     227          464 :       context->query_completed (reference);
     228          464 :       return true;
     229              :     }
     230              : 
     231              :   // is it an extern item?
     232           56 :   if (auto extern_item = mappings.lookup_hir_extern_item (reference))
     233              :     {
     234           53 :       auto block = mappings.lookup_hir_extern_block (extern_item->second);
     235           53 :       rust_assert (block.has_value ());
     236              : 
     237           53 :       *result
     238           53 :         = TypeCheckTopLevelExternItem::Resolve (*extern_item.value ().first,
     239           53 :                                                 *block.value ());
     240           53 :       context->query_completed (reference);
     241           53 :       return true;
     242              :     }
     243              : 
     244              :   // more?
     245            3 :   location_t possible_locus = mappings.lookup_location (reference);
     246            3 :   rust_debug_loc (possible_locus, "query system failed to resolve: [%u]",
     247              :                   reference);
     248            3 :   context->query_completed (reference);
     249              : 
     250            3 :   return false;
     251              : }
     252              : 
     253              : bool
     254       334462 : types_compatable (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
     255              :                   location_t unify_locus, bool emit_errors, bool check_bounds)
     256              : {
     257       334462 :   TyTy::BaseType *result
     258       334462 :     = unify_site_and (UNKNOWN_HIRID, lhs, rhs, unify_locus, emit_errors,
     259              :                       false /*commit*/, true /*infer*/, true /*cleanup*/,
     260              :                       check_bounds);
     261       334462 :   return result->get_kind () != TyTy::TypeKind::ERROR;
     262              : }
     263              : 
     264              : TyTy::BaseType *
     265        32840 : unify_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
     266              :             location_t unify_locus)
     267              : {
     268        32840 :   TyTy::BaseType *expected = lhs.get_ty ();
     269        32840 :   TyTy::BaseType *expr = rhs.get_ty ();
     270              : 
     271        32840 :   rust_debug ("unify_site id={%u} expected={%s} expr={%s}", id,
     272              :               expected->debug_str ().c_str (), expr->debug_str ().c_str ());
     273              : 
     274        32840 :   std::vector<UnifyRules::CommitSite> commits;
     275        32840 :   std::vector<UnifyRules::InferenceSite> infers;
     276        32840 :   return UnifyRules::Resolve (lhs, rhs, unify_locus, true /*commit*/,
     277              :                               true /*emit_error*/, true /*check_bounds*/,
     278        32840 :                               false /*infer*/, commits, infers);
     279        32840 : }
     280              : 
     281              : TyTy::BaseType *
     282       464238 : unify_site_and (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
     283              :                 location_t unify_locus, bool emit_errors, bool commit_if_ok,
     284              :                 bool implicit_infer_vars, bool cleanup, bool check_bounds)
     285              : {
     286       464238 :   TypeCheckContext &context = *TypeCheckContext::get ();
     287              : 
     288       464238 :   TyTy::BaseType *expected = lhs.get_ty ();
     289       464238 :   TyTy::BaseType *expr = rhs.get_ty ();
     290              : 
     291       464239 :   rust_debug_loc (unify_locus,
     292              :                   "begin unify_site_and commit %s infer %s check_bounds %s "
     293              :                   "id={%u} expected={%s} expr={%s}",
     294              :                   commit_if_ok ? "true" : "false",
     295              :                   implicit_infer_vars ? "true" : "false",
     296              :                   check_bounds ? "true" : "false", id == UNKNOWN_HIRID ? 0 : id,
     297              :                   expected->debug_str ().c_str (), expr->debug_str ().c_str ());
     298              : 
     299       464238 :   std::vector<UnifyRules::CommitSite> commits;
     300       464238 :   std::vector<UnifyRules::InferenceSite> infers;
     301       464238 :   TyTy::BaseType *result
     302       464238 :     = UnifyRules::Resolve (lhs, rhs, unify_locus, false /*commit inline*/,
     303              :                            emit_errors, check_bounds, implicit_infer_vars,
     304              :                            commits, infers);
     305       464238 :   bool ok = result->get_kind () != TyTy::TypeKind::ERROR;
     306              : 
     307       464239 :   rust_debug_loc (unify_locus,
     308              :                   "unify_site_and done ok=%s commit %s infer %s id={%u} "
     309              :                   "expected={%s} expr={%s}",
     310              :                   ok ? "true" : "false", commit_if_ok ? "true" : "false",
     311              :                   implicit_infer_vars ? "true" : "false",
     312              :                   id == UNKNOWN_HIRID ? 0 : id, expected->debug_str ().c_str (),
     313              :                   expr->debug_str ().c_str ());
     314              : 
     315       464238 :   if (ok && commit_if_ok)
     316              :     {
     317       226516 :       for (auto &c : commits)
     318              :         {
     319       132894 :           UnifyRules::commit (c.lhs, c.rhs, c.resolved);
     320              :         }
     321              :     }
     322       370616 :   else if (cleanup)
     323              :     {
     324       374988 :       for (auto &i : infers)
     325              :         {
     326         4710 :           if (i.param != nullptr)
     327              :             {
     328         4666 :               i.param->set_ref (i.pref);
     329         4666 :               i.param->set_ty_ref (i.ptyref);
     330              :             }
     331              : 
     332              :           // remove the inference variable
     333         4710 :           context.clear_type (i.infer);
     334              :           // FIXME: Don't delete - result might point to this
     335              :           // delete i.infer;
     336              :         }
     337              :     }
     338       464238 :   return result;
     339       464238 : }
     340              : 
     341              : TyTy::BaseType *
     342        43506 : coercion_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
     343              :                location_t locus)
     344              : {
     345        43506 :   TyTy::BaseType *expected = lhs.get_ty ();
     346        43506 :   TyTy::BaseType *expr = rhs.get_ty ();
     347              : 
     348        43506 :   rust_debug ("coercion_site id={%u} expected={%s} expr={%s}", id,
     349              :               expected->debug_str ().c_str (), expr->debug_str ().c_str ());
     350              : 
     351        43506 :   auto context = TypeCheckContext::get ();
     352        43506 :   if (expected->get_kind () == TyTy::TypeKind::ERROR
     353        43506 :       || expr->get_kind () == TyTy::TypeKind::ERROR)
     354              :     return expr;
     355              : 
     356              :   // can we autoderef it?
     357        43484 :   auto result = TypeCoercionRules::Coerce (expr, expected, locus,
     358        43484 :                                            true /*allow-autodref*/);
     359              : 
     360              :   // the result needs to be unified
     361        43484 :   TyTy::BaseType *receiver = expr;
     362        43484 :   if (!result.is_error ())
     363              :     {
     364        43429 :       receiver = result.tyty;
     365              :     }
     366              : 
     367        43484 :   rust_debug ("coerce_default_unify(a={%s}, b={%s})",
     368              :               receiver->debug_str ().c_str (), expected->debug_str ().c_str ());
     369        43484 :   TyTy::BaseType *coerced
     370        43484 :     = unify_site_and (id, lhs,
     371        43484 :                       TyTy::TyWithLocation (receiver, rhs.get_locus ()), locus,
     372              :                       true /*emit_error*/, true /*commit*/, true /*infer*/,
     373              :                       true /*cleanup*/);
     374        43484 :   context->insert_autoderef_mappings (id, std::move (result.adjustments));
     375        43484 :   return coerced;
     376        43484 : }
     377              : 
     378              : TyTy::BaseType *
     379         1630 : try_coercion (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
     380              :               location_t locus)
     381              : {
     382         1630 :   TyTy::BaseType *expected = lhs.get_ty ();
     383         1630 :   TyTy::BaseType *expr = rhs.get_ty ();
     384              : 
     385         1630 :   rust_debug ("try_coercion_site id={%u} expected={%s} expr={%s}", id,
     386              :               expected->debug_str ().c_str (), expr->debug_str ().c_str ());
     387              : 
     388         1630 :   auto result = TypeCoercionRules::TryCoerce (expr, expected, locus,
     389         1630 :                                               true /*allow-autodref*/);
     390         1630 :   if (result.is_error ())
     391           97 :     return new TyTy::ErrorType (id);
     392              : 
     393         1533 :   return result.tyty;
     394         1630 : }
     395              : 
     396              : TyTy::BaseType *
     397         5757 : cast_site (HirId id, TyTy::TyWithLocation from, TyTy::TyWithLocation to,
     398              :            location_t cast_locus)
     399              : {
     400         5757 :   rust_debug ("cast_site id={%u} from={%s} to={%s}", id,
     401              :               from.get_ty ()->debug_str ().c_str (),
     402              :               to.get_ty ()->debug_str ().c_str ());
     403              : 
     404         5757 :   auto context = TypeCheckContext::get ();
     405         5757 :   if (from.get_ty ()->get_kind () == TyTy::TypeKind::ERROR
     406         5757 :       || to.get_ty ()->get_kind () == TyTy::TypeKind::ERROR)
     407              :     return to.get_ty ();
     408              : 
     409              :   // do the cast
     410         5757 :   auto result = TypeCastRules::resolve (cast_locus, from, to);
     411              : 
     412              :   // we assume error has already been emitted
     413         5757 :   if (result.is_error ())
     414              :     return to.get_ty ();
     415              : 
     416              :   // the result needs to be unified
     417         5741 :   TyTy::BaseType *casted_result = result.tyty;
     418         5741 :   rust_debug ("cast_default_unify(a={%s}, b={%s})",
     419              :               casted_result->debug_str ().c_str (),
     420              :               to.get_ty ()->debug_str ().c_str ());
     421              : 
     422         5741 :   TyTy::BaseType *casted
     423         5741 :     = unify_site (id, to,
     424         5741 :                   TyTy::TyWithLocation (casted_result, from.get_locus ()),
     425              :                   cast_locus);
     426         5741 :   context->insert_cast_autoderef_mappings (id, std::move (result.adjustments));
     427         5741 :   return casted;
     428         5757 : }
     429              : 
     430              : AssociatedImplTrait *
     431        11292 : lookup_associated_impl_block (const TyTy::TypeBoundPredicate &bound,
     432              :                               TyTy::BaseType *binding, bool *ambigious)
     433              : {
     434        11292 :   auto context = TypeCheckContext::get ();
     435              : 
     436              :   // setup any associated type mappings for the specified bonds and this
     437              :   // type
     438        11292 :   auto candidates
     439        11292 :     = TypeBoundsProbe::Probe (binding, bound.get ()->get_hir_trait_ref ());
     440        11292 :   std::vector<AssociatedImplTrait *> associated_impl_traits;
     441        25174 :   for (auto &probed_bound : candidates)
     442              :     {
     443        13882 :       HIR::ImplBlock *associated_impl = probed_bound.second;
     444              : 
     445        13882 :       HirId impl_block_id = associated_impl->get_mappings ().get_hirid ();
     446        13882 :       AssociatedImplTrait *associated = nullptr;
     447        13882 :       bool found_impl_trait
     448        13882 :         = context->lookup_associated_trait_impl (impl_block_id, &associated);
     449        13882 :       if (found_impl_trait)
     450              :         {
     451              :           // compare the bounds from here i think is what we can do:
     452         2598 :           if (bound.get ()->is_equal (*associated->get_predicate ().get ()))
     453              :             {
     454         2598 :               associated_impl_traits.push_back (associated);
     455              :             }
     456              :         }
     457              :     }
     458              : 
     459        11292 :   if (associated_impl_traits.empty ())
     460              :     return nullptr;
     461              : 
     462              :   // This code is important when you look at slices for example when
     463              :   // you have a slice such as:
     464              :   //
     465              :   // let slice = &array[1..3]
     466              :   //
     467              :   // the higher ranked bounds will end up having an Index trait
     468              :   // implementation for Range<usize> so we need this code to resolve
     469              :   // that we have an integer inference variable that needs to become
     470              :   // a usize
     471              :   //
     472              :   // The other complicated issue is that we might have an intrinsic
     473              :   // which requires the :Clone or Copy bound but the libcore adds
     474              :   // implementations for all the integral types so when there are
     475              :   // multiple candidates we need to resolve to the default
     476              :   // implementation for that type otherwise its an error for
     477              :   // ambiguous type bounds
     478              : 
     479              :   // if we have a non-general inference variable we need to be
     480              :   // careful about the selection here
     481         2560 :   bool is_infer_var = binding->get_kind () == TyTy::TypeKind::INFER;
     482         2560 :   bool is_integer_infervar
     483              :     = is_infer_var
     484         2560 :       && static_cast<const TyTy::InferType *> (binding)->get_infer_kind ()
     485         2624 :            == TyTy::InferType::InferTypeKind::INTEGRAL;
     486           64 :   bool is_float_infervar
     487              :     = is_infer_var
     488           64 :       && static_cast<const TyTy::InferType *> (binding)->get_infer_kind ()
     489         2560 :            == TyTy::InferType::InferTypeKind::FLOAT;
     490              : 
     491         2560 :   AssociatedImplTrait *associate_impl_trait = nullptr;
     492         2560 :   if (associated_impl_traits.size () == 1)
     493              :     {
     494              :       // just go for it
     495         2522 :       associate_impl_trait = associated_impl_traits.at (0);
     496              :     }
     497           38 :   else if (is_integer_infervar)
     498              :     {
     499            0 :       TyTy::BaseType *type = nullptr;
     500            0 :       bool ok = context->lookup_builtin ("i32", &type);
     501            0 :       rust_assert (ok);
     502              : 
     503            0 :       for (auto &impl : associated_impl_traits)
     504              :         {
     505            0 :           bool found = impl->get_self ()->is_equal (*type);
     506            0 :           if (found)
     507              :             {
     508            0 :               associate_impl_trait = impl;
     509            0 :               break;
     510              :             }
     511              :         }
     512              :     }
     513           38 :   else if (is_float_infervar)
     514              :     {
     515            0 :       TyTy::BaseType *type = nullptr;
     516            0 :       bool ok = context->lookup_builtin ("f64", &type);
     517            0 :       rust_assert (ok);
     518              : 
     519            0 :       for (auto &impl : associated_impl_traits)
     520              :         {
     521            0 :           bool found = impl->get_self ()->is_equal (*type);
     522            0 :           if (found)
     523              :             {
     524            0 :               associate_impl_trait = impl;
     525            0 :               break;
     526              :             }
     527              :         }
     528              :     }
     529              : 
     530         2560 :   if (associate_impl_trait == nullptr && ambigious != nullptr)
     531              :     {
     532           37 :       *ambigious = true;
     533              :     }
     534              : 
     535              :   return associate_impl_trait;
     536        11292 : }
     537              : 
     538              : void
     539        11548 : rebind_projection_self_from_fn (TyTy::FnType &fn, TyTy::BaseType *root)
     540              : {
     541              :   // After substitution+monomorphize the fn's substitution clones carry the
     542              :   // call-site bindings. Inner projections in the return/params can still
     543              :   // reference the traits formal Self via TyVar(formal.ref) whose type table
     544              :   // entry resolves to the unbound formal
     545        11548 :   std::map<HirId, TyTy::BaseGeneric *> bound_by_formal;
     546        17262 :   for (auto &sub : fn.get_substs ())
     547              :     {
     548         5714 :       auto *pty = sub.get_param_ty ();
     549         5714 :       if (pty == nullptr || pty->get_kind () != TyTy::TypeKind::PARAM
     550        11421 :           || !pty->can_resolve ())
     551          102 :         continue;
     552         5612 :       bound_by_formal[pty->get_ref ()] = pty;
     553              :     }
     554              : 
     555        11548 :   std::function<void (TyTy::BaseType *)> rebind;
     556        36971 :   rebind = [&] (TyTy::BaseType *ty) {
     557        13875 :     if (ty == nullptr)
     558              :       return;
     559              : 
     560        13875 :     if (auto *proj = ty->try_as<TyTy::ProjectionType> ())
     561              :       {
     562          203 :         auto *self = proj->get_self ();
     563          203 :         if (self->get_kind () == TyTy::TypeKind::PARAM)
     564              :           {
     565          172 :             auto it = bound_by_formal.find (self->get_ref ());
     566          172 :             if (it != bound_by_formal.end ())
     567          158 :               proj->set_self (it->second);
     568              :           }
     569              : 
     570          517 :         for (auto &sub : proj->get_substs ())
     571              :           {
     572          314 :             auto *param = sub.get_param_ty ();
     573          314 :             if (param == nullptr || param->get_kind () != TyTy::TypeKind::PARAM
     574          628 :                 || param->can_resolve ())
     575          276 :               continue;
     576              : 
     577           38 :             auto it = bound_by_formal.find (param->get_ref ());
     578           38 :             if (it == bound_by_formal.end ()
     579           38 :                 || it->second->get_kind () != TyTy::TypeKind::PARAM)
     580            0 :               continue;
     581              : 
     582           38 :             auto *bound = static_cast<TyTy::ParamType *> (it->second);
     583           38 :             if (bound->can_resolve ())
     584           38 :               param->set_ty_ref (bound->get_ty_ref ());
     585              :           }
     586              :         return;
     587              :       }
     588              : 
     589        13672 :     if (auto *adt = ty->try_as<TyTy::ADTType> ())
     590              :       {
     591         2783 :         for (auto &variant : adt->get_variants ())
     592         3302 :           for (auto &field : variant->get_fields ())
     593         1587 :             rebind (field->get_field_type ());
     594              :         return;
     595              :       }
     596              : 
     597        12604 :     if (auto *ref = ty->try_as<TyTy::ReferenceType> ())
     598           55 :       rebind (ref->get_base ());
     599        12549 :     else if (auto *ptr = ty->try_as<TyTy::PointerType> ())
     600          229 :       rebind (ptr->get_base ());
     601        12320 :     else if (auto *tup = ty->try_as<TyTy::TupleType> ())
     602         4962 :       for (size_t i = 0; i < tup->num_fields (); i++)
     603          456 :         rebind (tup->get_field (i));
     604        11548 :   };
     605              : 
     606        11548 :   rebind (root);
     607        11548 : }
     608              : 
     609              : TyTy::BaseType *
     610         4394 : normalize_projection (TyTy::ProjectionType *proj, location_t locus,
     611              :                       bool emit_errors, bool unify_self)
     612              : {
     613         4948 :   static std::vector<TyTy::ProjectionType *> active_projections;
     614         8788 :   if (ScopedPush<TyTy::ProjectionType *>::contains (active_projections, proj))
     615              :     return proj;
     616              : 
     617         4394 :   ScopedPush<TyTy::ProjectionType *> guard (active_projections, proj);
     618              : 
     619         4394 :   if (!proj->is_trait_position ())
     620              :     {
     621          438 :       TyTy::BaseType *base = proj->get ();
     622          438 :       if (auto *param = base->try_as<TyTy::ParamType> ())
     623              :         {
     624          106 :           if (param->can_resolve ())
     625              :             {
     626          106 :               TyTy::BaseType *resolved
     627          106 :                 = TyTy::TyVar (param->get_ty_ref ()).get_tyty ();
     628          106 :               if (!resolved->is<TyTy::ParamType> ())
     629          438 :                 base = resolved;
     630              :             }
     631              :         }
     632         4832 :       if (auto *base_proj = base->try_as<TyTy::ProjectionType> ())
     633            0 :         return normalize_projection (base_proj, locus, emit_errors, unify_self);
     634              :       return base;
     635              :     }
     636              : 
     637              :   // special case the discriminant_type lang item
     638         3956 :   auto &mappings = Analysis::Mappings::get ();
     639         3956 :   auto *ctx = TypeCheckContext::get ();
     640         3956 :   if (auto discriminant_type_id
     641         3956 :       = mappings.lookup_lang_item (LangItem::Kind::DISCRIMINANT_TYPE))
     642              :     {
     643           72 :       if (proj->get_item_defid () == discriminant_type_id.value ())
     644              :         {
     645           72 :           TyTy::BaseType *isize_ty = nullptr;
     646           72 :           bool ok = ctx->lookup_builtin ("isize", &isize_ty);
     647           72 :           rust_assert (ok);
     648              : 
     649              :           // If the self type is a concrete ADT, use its repr.
     650           72 :           TyTy::BaseType *self = proj->get_self ()->destructure ();
     651           72 :           if (auto *adt = self->try_as<TyTy::ADTType> ())
     652              :             {
     653            0 :               auto *repr = adt->get_repr_options ().repr;
     654            0 :               if (repr != nullptr)
     655              :                 return repr;
     656              :             }
     657           72 :           return isize_ty;
     658              :         }
     659              :     }
     660              : 
     661         3884 :   ImplTraitContextFrame frame;
     662         3884 :   if (!ctx->find_matching_impl_trait_frame (*proj->get_trait_ref (),
     663         3884 :                                             *proj->get_self (), &frame))
     664              :     {
     665              :       // No concrete impl frame check WHERE clause bindings on the self type
     666              :       //
     667              :       //   fn foo<T: Trait<AssocType = X>>()
     668              :       //
     669              :       // normalizes
     670              :       //
     671              :       //    <T as Trait>::AssocType -> X.
     672              : 
     673         2594 :       TyTy::BaseType *self = proj->get_self ()->destructure ();
     674         2594 :       const DefId item_defid = proj->get_item_defid ();
     675              : 
     676              :       // find the name of the associated type from the trait reference
     677         2594 :       std::string assoc_name;
     678         2833 :       for (const auto &ti : proj->get_trait_ref ()->get_trait_items ())
     679              :         {
     680         3072 :           if (ti.get_mappings ().get_defid () == item_defid)
     681              :             {
     682         2594 :               assoc_name = ti.get_identifier ();
     683         2594 :               break;
     684              :             }
     685              :         }
     686              : 
     687         2594 :       if (!assoc_name.empty ())
     688              :         {
     689         4254 :           for (auto &bound : self->get_specified_bounds ())
     690              :             {
     691         1735 :               if (!bound.get ()->is_equal (*proj->get_trait_ref ()))
     692          420 :                 continue;
     693              : 
     694         1315 :               auto &binding
     695         1315 :                 = bound.get_substitution_arguments ().get_binding_args ();
     696         1315 :               auto it = binding.find (assoc_name);
     697         1315 :               if (it != binding.end ())
     698         2594 :                 return it->second;
     699              : 
     700         1255 :               const auto &constraints
     701         1255 :                 = bound.get_substitution_arguments ().get_constraint_args ();
     702         1255 :               auto constraint = constraints.find (assoc_name);
     703         1255 :               if (constraint != constraints.end ())
     704              :                 {
     705           15 :                   TyTy::BaseType *constrained = proj->clone ();
     706           15 :                   constrained->inherit_bounds (*constraint->second);
     707              : 
     708              :                   // Keep the constrained projection distinct from the canonical
     709              :                   // associated-type declaration.
     710           15 :                   auto &mappings = Analysis::Mappings::get ();
     711           15 :                   HirId fresh = mappings.get_next_hir_id ();
     712           15 :                   constrained->set_ref (fresh);
     713           15 :                   constrained->set_ty_ref (fresh);
     714           15 :                   ctx->insert_implicit_type (fresh, constrained);
     715           15 :                   return constrained;
     716              :                 }
     717              :             }
     718              :         }
     719              : 
     720              :       // If self is a trait-position projection recursively normalize it first
     721              :       // so the impl-block lookup below works on a concrete type.
     722         2519 :       if (auto *self_proj = self->try_as<TyTy::ProjectionType> ())
     723              :         {
     724           42 :           if (self_proj->is_trait_position ())
     725              :             {
     726            5 :               auto *norm = normalize_projection (self_proj, locus, emit_errors,
     727              :                                                  unify_self);
     728            5 :               if (norm != self_proj
     729            5 :                   && norm->get_kind () != TyTy::TypeKind::ERROR)
     730            4 :                 self = norm->destructure ();
     731              :             }
     732              :           else
     733              :             {
     734           37 :               auto *base = self_proj->get ();
     735           37 :               if (base && base != self_proj)
     736           37 :                 self = base->destructure ();
     737              :             }
     738              :         }
     739              : 
     740              :       // Direct impl-block lookup for concrete self types (no active frame).
     741         2519 :       if (!assoc_name.empty () && self->get_kind () != TyTy::TypeKind::PARAM
     742         1395 :           && self->get_kind () != TyTy::TypeKind::INFER
     743         3914 :           && self->get_kind () != TyTy::TypeKind::PROJECTION)
     744              :         {
     745         1390 :           auto candidates = TypeBoundsProbe::Probe (
     746         1390 :             self, proj->get_trait_ref ()->get_hir_trait_ref ());
     747         1590 :           for (auto &probed : candidates)
     748              :             {
     749         1490 :               HIR::ImplBlock *impl_block = probed.second;
     750         1490 :               if (!impl_block->has_trait_ref ())
     751          200 :                 continue;
     752              : 
     753         1290 :               HIR::TypePath &ref = impl_block->get_trait_ref ();
     754         1290 :               auto *tref = TraitResolver::Resolve (ref);
     755         1290 :               if (tref->is_error ()
     756         1290 :                   || !tref->is_equal (*proj->get_trait_ref ()))
     757            0 :                 continue;
     758              : 
     759         1459 :               for (auto &impl_item : impl_block->get_impl_items ())
     760              :                 {
     761         2918 :                   if (impl_item->get_impl_item_name ().compare (assoc_name)
     762         1459 :                       != 0)
     763          169 :                     continue;
     764              : 
     765         1290 :                   TyTy::BaseType *result = nullptr;
     766         1290 :                   if (query_type (impl_item->get_impl_mappings ().get_hirid (),
     767              :                                   &result))
     768              :                     {
     769         1290 :                       AssociatedImplTrait *associated = nullptr;
     770         1290 :                       if (ctx->lookup_associated_trait_impl (
     771         1290 :                             impl_block->get_mappings ().get_hirid (),
     772              :                             &associated)
     773         1290 :                           && associated != nullptr)
     774              :                         {
     775         1227 :                           auto mapping
     776              :                             = associated->bind_impl_for_projection (*proj,
     777         1227 :                                                                     locus);
     778         1227 :                           if (!mapping.is_error ())
     779         1220 :                             result
     780         1220 :                               = SubstMapperInternal::Resolve (result, mapping);
     781         1227 :                         }
     782              : 
     783              :                       // impl type aliases are stored as non-trait-position
     784              :                       // ProjectionType; unwrap to base only when there are no
     785              :                       // substitution params (non-GAT)
     786         1290 :                       if (auto *p = result->try_as<TyTy::ProjectionType> ())
     787              :                         {
     788         1290 :                           if (!p->is_trait_position ())
     789              :                             {
     790         1290 :                               bool all_substs_bound = true;
     791         1728 :                               for (auto &s : p->get_substs ())
     792              :                                 {
     793          747 :                                   auto *sp = s.get_param_ty ();
     794          747 :                                   if (sp == nullptr || !sp->can_resolve ()
     795         1255 :                                       || sp->resolve ()->get_kind ()
     796              :                                            == TyTy::TypeKind::PARAM)
     797              :                                     {
     798              :                                       all_substs_bound = false;
     799              :                                       break;
     800              :                                     }
     801              :                                 }
     802              : 
     803              :                               // Also unwrap when the base is already concrete
     804         1290 :                               bool base_is_concrete
     805         1290 :                                 = p->get () != nullptr
     806         1290 :                                   && p->get ()->is_concrete ();
     807         1290 :                               if (!p->has_substitutions () || all_substs_bound
     808         1290 :                                   || base_is_concrete)
     809         1257 :                                 result = p->get ();
     810              :                             }
     811              :                         }
     812              : 
     813         1290 :                       return result;
     814              :                     }
     815            0 :                   break;
     816              :                 }
     817              :             }
     818         1390 :         }
     819              : 
     820              :       // special-case FnOnce::Output
     821         1229 :       if (proj->is_trait_position ())
     822              :         {
     823         1229 :           auto fn_once_lookup
     824         1229 :             = mappings.lookup_lang_item (LangItem::Kind::FN_ONCE);
     825         1229 :           auto fn_once_output_lookup
     826         1229 :             = mappings.lookup_lang_item (LangItem::Kind::FN_ONCE_OUTPUT);
     827         1229 :           if (!fn_once_lookup || !fn_once_output_lookup)
     828         1167 :             return proj;
     829              : 
     830          162 :           DefId &fn_once_trait_id = fn_once_lookup.value ();
     831          162 :           DefId &fn_once_output_id = fn_once_output_lookup.value ();
     832          162 :           DefId proj_trait_id = proj->get_trait_ref ()->get_defid ();
     833          162 :           DefId proj_trait_item_id = proj->get_item_defid ();
     834              : 
     835          324 :           if (proj_trait_id == fn_once_trait_id
     836          224 :               && proj_trait_item_id == fn_once_output_id)
     837              :             {
     838          162 :               auto pself = proj->get_self ();
     839          224 :               if (auto closure = pself->try_as<TyTy::ClosureType> ())
     840          100 :                 return &closure->get_result_type ();
     841              :             }
     842              :         }
     843              : 
     844              :       return proj;
     845         2594 :     }
     846              : 
     847         1290 :   if (unify_self)
     848              :     {
     849            0 :       TyTy::BaseType *proj_self = proj->get_self ();
     850            0 :       TyTy::BaseType *impl_self = frame.self;
     851            0 :       TyTy::BaseType *self
     852            0 :         = unify_site_and (/*id*/ 0, TyTy::TyWithLocation (proj_self, locus),
     853            0 :                           TyTy::TyWithLocation (impl_self, locus), locus,
     854              :                           /*emit_errors*/ false,
     855              :                           /*commit*/ false,
     856              :                           /*infer*/ false,
     857              :                           /*cleanup*/ true,
     858              :                           /*check_bounds*/ false);
     859              : 
     860            0 :       if (self->get_kind () == TyTy::TypeKind::ERROR)
     861              :         return self;
     862              :     }
     863              : 
     864              :   // Lookup the trait item -> impl type mapping (key = trait item DefId).
     865         1290 :   const DefId item = proj->get_item_defid ();
     866         1290 :   auto it = frame.assoc_types_by_trait_item.find (item);
     867         1290 :   if (it == frame.assoc_types_by_trait_item.end ())
     868              :     {
     869              :       return proj;
     870              :     }
     871              : 
     872         1290 :   auto &entry = it->second;
     873         1290 :   auto impl_value = entry.value;
     874              : 
     875              :   // chase the impl body through any further projections it contains
     876         1290 :   TyTy::BaseType *normalized = impl_value;
     877         2580 :   for (size_t i = 0; i < kNormalizeProjectionLimit; i++)
     878              :     {
     879         2580 :       if (!normalized->is<TyTy::ProjectionType> ())
     880              :         break;
     881              : 
     882         1339 :       auto p = normalized->as<TyTy::ProjectionType> ();
     883         1339 :       if (p->is_trait_position ())
     884              :         {
     885           49 :           auto *n = normalize_projection (p, locus, emit_errors, unify_self);
     886           49 :           if (n == p)
     887              :             break;
     888              : 
     889              :           normalized = n;
     890              :         }
     891              :       else
     892              :         {
     893         1290 :           auto *v = p->get ();
     894         1290 :           if (v == nullptr || v == p)
     895              :             break;
     896              : 
     897              :           normalized = v;
     898              :         }
     899              :     }
     900              : 
     901              :   return normalized;
     902         4394 : }
     903              : 
     904              : } // namespace Resolver
     905              : } // 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.