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

Generated by: LCOV version 2.5.0-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.