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