LCOV - code coverage report
Current view: top level - gcc/rust/typecheck - rust-type-util.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 91.5 % 189 173
Test Date: 2026-02-28 14:20:25 Functions: 100.0 % 8 8
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-type-util.h"
      20              : #include "rust-diagnostics.h"
      21              : #include "rust-hir-map.h"
      22              : #include "rust-hir-type-check-implitem.h"
      23              : #include "rust-hir-type-check-item.h"
      24              : #include "rust-hir-type-check.h"
      25              : #include "rust-hir-type-check-type.h"
      26              : #include "rust-casts.h"
      27              : #include "rust-mapping-common.h"
      28              : #include "rust-unify.h"
      29              : #include "rust-coercion.h"
      30              : #include "rust-hir-type-bounds.h"
      31              : #include "rust-immutable-name-resolution-context.h"
      32              : #include "options.h"
      33              : 
      34              : namespace Rust {
      35              : namespace Resolver {
      36              : 
      37              : bool
      38      1985983 : query_type (HirId reference, TyTy::BaseType **result)
      39              : {
      40      1985983 :   auto &mappings = Analysis::Mappings::get ();
      41      1985983 :   TypeCheckContext *context = TypeCheckContext::get ();
      42              : 
      43      1985983 :   if (context->lookup_type (reference, result))
      44              :     return true;
      45              : 
      46        14188 :   if (context->query_in_progress (reference))
      47              :     return false;
      48              : 
      49        11177 :   context->insert_query (reference);
      50              : 
      51        11177 :   std::pair<HIR::Enum *, HIR::EnumItem *> enum_candidiate
      52        11177 :     = mappings.lookup_hir_enumitem (reference);
      53        22354 :   bool enum_candidiate_ok
      54        11177 :     = enum_candidiate.first != nullptr && enum_candidiate.second != nullptr;
      55        11177 :   if (enum_candidiate_ok)
      56              :     {
      57         4239 :       HIR::Enum *parent = enum_candidiate.first;
      58         4239 :       HIR::EnumItem *enum_item = enum_candidiate.second;
      59         4239 :       rust_debug_loc (enum_item->get_locus (), "resolved item {%u} to",
      60              :                       reference);
      61              : 
      62         4239 :       *result = TypeCheckItem::Resolve (*parent);
      63              : 
      64         4239 :       context->query_completed (reference);
      65         4239 :       return true;
      66              :     }
      67              : 
      68         6938 :   if (auto item = mappings.lookup_hir_item (reference))
      69              :     {
      70         1001 :       rust_debug_loc (item.value ()->get_locus (), "resolved item {%u} to",
      71              :                       reference);
      72         1001 :       *result = TypeCheckItem::Resolve (*item.value ());
      73         1001 :       context->query_completed (reference);
      74         1001 :       return true;
      75              :     }
      76              : 
      77         5937 :   if (auto impl_item = mappings.lookup_hir_implitem (reference))
      78              :     {
      79         3279 :       auto impl_block
      80         3279 :         = mappings.lookup_hir_impl_block (impl_item->second).value ();
      81              : 
      82              :       // found an impl item
      83         3279 :       rust_debug_loc (impl_item->first->get_locus (),
      84              :                       "resolved impl-item {%u} to", reference);
      85              : 
      86         3279 :       *result = TypeCheckItem::ResolveImplItem (*impl_block, *impl_item->first);
      87         3279 :       context->query_completed (reference);
      88         3279 :       return true;
      89              :     }
      90              : 
      91              :   // is it an impl_type?
      92         2658 :   if (auto impl_block_by_type = mappings.lookup_impl_block_type (reference))
      93              :     {
      94              :       // found an impl item
      95         2597 :       HIR::ImplBlock *impl = impl_block_by_type.value ();
      96         2597 :       rust_debug_loc (impl->get_locus (), "resolved impl block type {%u} to",
      97              :                       reference);
      98              : 
      99              :       // this could be recursive to the root type
     100         2597 :       if (impl->has_type ())
     101              :         {
     102         2597 :           HIR::Type &ty = impl->get_type ();
     103         2597 :           NodeId ref_node_id = UNKNOWN_NODEID;
     104         2597 :           NodeId ast_node_id = ty.get_mappings ().get_nodeid ();
     105              : 
     106         2597 :           auto &nr_ctx
     107         2597 :             = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
     108              : 
     109              :           // assign the ref_node_id if we've found something
     110         2597 :           nr_ctx.lookup (ast_node_id).map ([&ref_node_id] (NodeId resolved) {
     111         2526 :             ref_node_id = resolved;
     112              :           });
     113              : 
     114         2597 :           if (ref_node_id != UNKNOWN_NODEID)
     115              :             {
     116         2526 :               tl::optional<HirId> hid
     117         2526 :                 = mappings.lookup_node_to_hir (ref_node_id);
     118         2526 :               if (hid.has_value () && context->query_in_progress (hid.value ()))
     119              :                 {
     120            2 :                   context->query_completed (reference);
     121            2 :                   return false;
     122              :                 }
     123              :             }
     124              :         }
     125              : 
     126         2595 :       *result = TypeCheckItem::ResolveImplBlockSelf (*impl);
     127         2595 :       context->query_completed (reference);
     128         2595 :       return true;
     129              :     }
     130              : 
     131              :   // is it an extern item?
     132           61 :   if (auto extern_item = mappings.lookup_hir_extern_item (reference))
     133              :     {
     134           58 :       auto block = mappings.lookup_hir_extern_block (extern_item->second);
     135           58 :       rust_assert (block.has_value ());
     136              : 
     137           58 :       *result
     138           58 :         = TypeCheckTopLevelExternItem::Resolve (*extern_item.value ().first,
     139           58 :                                                 *block.value ());
     140           58 :       context->query_completed (reference);
     141           58 :       return true;
     142              :     }
     143              : 
     144              :   // more?
     145            3 :   location_t possible_locus = mappings.lookup_location (reference);
     146            3 :   rust_debug_loc (possible_locus, "query system failed to resolve: [%u]",
     147              :                   reference);
     148            3 :   context->query_completed (reference);
     149              : 
     150            3 :   return false;
     151              : }
     152              : 
     153              : bool
     154      1886863 : types_compatable (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
     155              :                   location_t unify_locus, bool emit_errors, bool check_bounds)
     156              : {
     157      1886863 :   TyTy::BaseType *result
     158      1886863 :     = unify_site_and (UNKNOWN_HIRID, lhs, rhs, unify_locus, emit_errors,
     159              :                       false /*commit*/, true /*infer*/, true /*cleanup*/,
     160              :                       check_bounds);
     161      1886863 :   return result->get_kind () != TyTy::TypeKind::ERROR;
     162              : }
     163              : 
     164              : TyTy::BaseType *
     165        29056 : unify_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
     166              :             location_t unify_locus)
     167              : {
     168        29056 :   TyTy::BaseType *expected = lhs.get_ty ();
     169        29056 :   TyTy::BaseType *expr = rhs.get_ty ();
     170              : 
     171        29056 :   rust_debug ("unify_site id={%u} expected={%s} expr={%s}", id,
     172              :               expected->debug_str ().c_str (), expr->debug_str ().c_str ());
     173              : 
     174        29056 :   std::vector<UnifyRules::CommitSite> commits;
     175        29056 :   std::vector<UnifyRules::InferenceSite> infers;
     176        29056 :   return UnifyRules::Resolve (lhs, rhs, unify_locus, true /*commit*/,
     177              :                               true /*emit_error*/, false /*infer*/,
     178        29056 :                               true /*check_bounds*/, commits, infers);
     179        29056 : }
     180              : 
     181              : TyTy::BaseType *
     182      2008793 : unify_site_and (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
     183              :                 location_t unify_locus, bool emit_errors, bool commit_if_ok,
     184              :                 bool implicit_infer_vars, bool cleanup, bool check_bounds)
     185              : {
     186      2008793 :   TypeCheckContext &context = *TypeCheckContext::get ();
     187              : 
     188      2008793 :   TyTy::BaseType *expected = lhs.get_ty ();
     189      2008793 :   TyTy::BaseType *expr = rhs.get_ty ();
     190              : 
     191      7682431 :   rust_debug_loc (unify_locus,
     192              :                   "begin unify_site_and commit %s infer %s check_bounds %s "
     193              :                   "id={%u} expected={%s} expr={%s}",
     194              :                   commit_if_ok ? "true" : "false",
     195              :                   implicit_infer_vars ? "true" : "false",
     196              :                   check_bounds ? "true" : "false", id == UNKNOWN_HIRID ? 0 : id,
     197      4017586 :                   expected->debug_str ().c_str (), expr->debug_str ().c_str ());
     198              : 
     199      2008793 :   std::vector<UnifyRules::CommitSite> commits;
     200      2008793 :   std::vector<UnifyRules::InferenceSite> infers;
     201      2008793 :   TyTy::BaseType *result
     202      2008793 :     = UnifyRules::Resolve (lhs, rhs, unify_locus, false /*commit inline*/,
     203              :                            emit_errors, implicit_infer_vars, check_bounds,
     204              :                            commits, infers);
     205      2008793 :   bool ok = result->get_kind () != TyTy::TypeKind::ERROR;
     206              : 
     207      3587378 :   rust_debug_loc (unify_locus,
     208              :                   "unify_site_and done ok=%s commit %s infer %s id={%u} "
     209              :                   "expected={%s} expr={%s}",
     210              :                   ok ? "true" : "false", commit_if_ok ? "true" : "false",
     211              :                   implicit_infer_vars ? "true" : "false",
     212      4017586 :                   id == UNKNOWN_HIRID ? 0 : id, expected->debug_str ().c_str (),
     213      2008793 :                   expr->debug_str ().c_str ());
     214              : 
     215      2008793 :   if (ok && commit_if_ok)
     216              :     {
     217       196459 :       for (auto &c : commits)
     218              :         {
     219       115503 :           UnifyRules::commit (c.lhs, c.rhs, c.resolved);
     220              :         }
     221              :     }
     222      1927837 :   else if (cleanup)
     223              :     {
     224      2012339 :       for (auto &i : infers)
     225              :         {
     226        84982 :           if (i.param != nullptr)
     227              :             {
     228        84933 :               i.param->set_ref (i.pref);
     229        84933 :               i.param->set_ty_ref (i.ptyref);
     230              :             }
     231              : 
     232              :           // remove the inference variable
     233        84982 :           context.clear_type (i.infer);
     234              :           // FIXME: Don't delete - result might point to this
     235              :           // delete i.infer;
     236              :         }
     237              :     }
     238      2008793 :   return result;
     239      2008793 : }
     240              : 
     241              : TyTy::BaseType *
     242        38313 : coercion_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
     243              :                location_t locus)
     244              : {
     245        38313 :   TyTy::BaseType *expected = lhs.get_ty ();
     246        38313 :   TyTy::BaseType *expr = rhs.get_ty ();
     247              : 
     248        38313 :   rust_debug ("coercion_site id={%u} expected={%s} expr={%s}", id,
     249              :               expected->debug_str ().c_str (), expr->debug_str ().c_str ());
     250              : 
     251        38313 :   auto context = TypeCheckContext::get ();
     252        38313 :   if (expected->get_kind () == TyTy::TypeKind::ERROR
     253        38313 :       || expr->get_kind () == TyTy::TypeKind::ERROR)
     254           20 :     return expr;
     255              : 
     256              :   // can we autoderef it?
     257        38293 :   auto result = TypeCoercionRules::Coerce (expr, expected, locus,
     258        38293 :                                            true /*allow-autodref*/);
     259              : 
     260              :   // the result needs to be unified
     261        38293 :   TyTy::BaseType *receiver = expr;
     262        38293 :   if (!result.is_error ())
     263              :     {
     264        38236 :       receiver = result.tyty;
     265              :     }
     266              : 
     267        38293 :   rust_debug ("coerce_default_unify(a={%s}, b={%s})",
     268              :               receiver->debug_str ().c_str (), expected->debug_str ().c_str ());
     269        38293 :   TyTy::BaseType *coerced
     270        38293 :     = unify_site_and (id, lhs,
     271        38293 :                       TyTy::TyWithLocation (receiver, rhs.get_locus ()), locus,
     272              :                       true /*emit_error*/, true /*commit*/, true /*infer*/,
     273              :                       true /*cleanup*/);
     274        38293 :   context->insert_autoderef_mappings (id, std::move (result.adjustments));
     275        38293 :   return coerced;
     276        38293 : }
     277              : 
     278              : TyTy::BaseType *
     279         1326 : try_coercion (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
     280              :               location_t locus)
     281              : {
     282         1326 :   TyTy::BaseType *expected = lhs.get_ty ();
     283         1326 :   TyTy::BaseType *expr = rhs.get_ty ();
     284              : 
     285         1326 :   rust_debug ("try_coercion_site id={%u} expected={%s} expr={%s}", id,
     286              :               expected->debug_str ().c_str (), expr->debug_str ().c_str ());
     287              : 
     288         1326 :   auto result = TypeCoercionRules::TryCoerce (expr, expected, locus,
     289         1326 :                                               true /*allow-autodref*/);
     290         1326 :   if (result.is_error ())
     291           27 :     return new TyTy::ErrorType (id);
     292              : 
     293         1299 :   return result.tyty;
     294         1326 : }
     295              : 
     296              : TyTy::BaseType *
     297         5177 : cast_site (HirId id, TyTy::TyWithLocation from, TyTy::TyWithLocation to,
     298              :            location_t cast_locus)
     299              : {
     300         5177 :   rust_debug ("cast_site id={%u} from={%s} to={%s}", id,
     301              :               from.get_ty ()->debug_str ().c_str (),
     302              :               to.get_ty ()->debug_str ().c_str ());
     303              : 
     304         5177 :   auto context = TypeCheckContext::get ();
     305         5177 :   if (from.get_ty ()->get_kind () == TyTy::TypeKind::ERROR
     306         5177 :       || to.get_ty ()->get_kind () == TyTy::TypeKind::ERROR)
     307              :     return to.get_ty ();
     308              : 
     309              :   // do the cast
     310         5177 :   auto result = TypeCastRules::resolve (cast_locus, from, to);
     311              : 
     312              :   // we assume error has already been emitted
     313         5177 :   if (result.is_error ())
     314              :     return to.get_ty ();
     315              : 
     316              :   // the result needs to be unified
     317         5161 :   TyTy::BaseType *casted_result = result.tyty;
     318         5161 :   rust_debug ("cast_default_unify(a={%s}, b={%s})",
     319              :               casted_result->debug_str ().c_str (),
     320              :               to.get_ty ()->debug_str ().c_str ());
     321              : 
     322         5161 :   TyTy::BaseType *casted
     323         5161 :     = unify_site (id, to,
     324         5161 :                   TyTy::TyWithLocation (casted_result, from.get_locus ()),
     325              :                   cast_locus);
     326         5161 :   context->insert_cast_autoderef_mappings (id, std::move (result.adjustments));
     327         5161 :   return casted;
     328         5177 : }
     329              : 
     330              : AssociatedImplTrait *
     331         8555 : lookup_associated_impl_block (const TyTy::TypeBoundPredicate &bound,
     332              :                               TyTy::BaseType *binding, bool *ambigious)
     333              : {
     334         8555 :   auto context = TypeCheckContext::get ();
     335              : 
     336              :   // setup any associated type mappings for the specified bonds and this
     337              :   // type
     338         8555 :   auto candidates = TypeBoundsProbe::Probe (binding);
     339         8555 :   std::vector<AssociatedImplTrait *> associated_impl_traits;
     340        49765 :   for (auto &probed_bound : candidates)
     341              :     {
     342        41210 :       HIR::ImplBlock *associated_impl = probed_bound.second;
     343              : 
     344        41210 :       HirId impl_block_id = associated_impl->get_mappings ().get_hirid ();
     345        41210 :       AssociatedImplTrait *associated = nullptr;
     346        41210 :       bool found_impl_trait
     347        41210 :         = context->lookup_associated_trait_impl (impl_block_id, &associated);
     348        41210 :       if (found_impl_trait)
     349              :         {
     350              :           // compare the bounds from here i think is what we can do:
     351        20536 :           if (bound.is_equal (associated->get_predicate ()))
     352              :             {
     353         2136 :               associated_impl_traits.push_back (associated);
     354              :             }
     355              :         }
     356              :     }
     357              : 
     358         8555 :   if (associated_impl_traits.empty ())
     359              :     return nullptr;
     360              : 
     361              :   // This code is important when you look at slices for example when
     362              :   // you have a slice such as:
     363              :   //
     364              :   // let slice = &array[1..3]
     365              :   //
     366              :   // the higher ranked bounds will end up having an Index trait
     367              :   // implementation for Range<usize> so we need this code to resolve
     368              :   // that we have an integer inference variable that needs to become
     369              :   // a usize
     370              :   //
     371              :   // The other complicated issue is that we might have an intrinsic
     372              :   // which requires the :Clone or Copy bound but the libcore adds
     373              :   // implementations for all the integral types so when there are
     374              :   // multiple candidates we need to resolve to the default
     375              :   // implementation for that type otherwise its an error for
     376              :   // ambiguous type bounds
     377              : 
     378              :   // if we have a non-general inference variable we need to be
     379              :   // careful about the selection here
     380         2114 :   bool is_infer_var = binding->get_kind () == TyTy::TypeKind::INFER;
     381         2114 :   bool is_integer_infervar
     382              :     = is_infer_var
     383         2114 :       && static_cast<const TyTy::InferType *> (binding)->get_infer_kind ()
     384         2184 :            == TyTy::InferType::InferTypeKind::INTEGRAL;
     385           70 :   bool is_float_infervar
     386              :     = is_infer_var
     387           70 :       && static_cast<const TyTy::InferType *> (binding)->get_infer_kind ()
     388         2114 :            == TyTy::InferType::InferTypeKind::FLOAT;
     389              : 
     390         2114 :   AssociatedImplTrait *associate_impl_trait = nullptr;
     391         2114 :   if (associated_impl_traits.size () == 1)
     392              :     {
     393              :       // just go for it
     394         2092 :       associate_impl_trait = associated_impl_traits.at (0);
     395              :     }
     396           22 :   else if (is_integer_infervar)
     397              :     {
     398            0 :       TyTy::BaseType *type = nullptr;
     399            0 :       bool ok = context->lookup_builtin ("i32", &type);
     400            0 :       rust_assert (ok);
     401              : 
     402            0 :       for (auto &impl : associated_impl_traits)
     403              :         {
     404            0 :           bool found = impl->get_self ()->is_equal (*type);
     405            0 :           if (found)
     406              :             {
     407            0 :               associate_impl_trait = impl;
     408            0 :               break;
     409              :             }
     410              :         }
     411              :     }
     412           22 :   else if (is_float_infervar)
     413              :     {
     414            0 :       TyTy::BaseType *type = nullptr;
     415            0 :       bool ok = context->lookup_builtin ("f64", &type);
     416            0 :       rust_assert (ok);
     417              : 
     418            0 :       for (auto &impl : associated_impl_traits)
     419              :         {
     420            0 :           bool found = impl->get_self ()->is_equal (*type);
     421            0 :           if (found)
     422              :             {
     423            0 :               associate_impl_trait = impl;
     424            0 :               break;
     425              :             }
     426              :         }
     427              :     }
     428              : 
     429         2114 :   if (associate_impl_trait == nullptr && ambigious != nullptr)
     430              :     {
     431           22 :       *ambigious = true;
     432              :     }
     433              : 
     434              :   return associate_impl_trait;
     435         8555 : }
     436              : 
     437              : } // namespace Resolver
     438              : } // 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.