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: 2025-11-22 14:42:49 Functions: 100.0 % 8 8
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : // Copyright (C) 2020-2025 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                 :     1985734 : query_type (HirId reference, TyTy::BaseType **result)
      39                 :             : {
      40                 :     1985734 :   auto &mappings = Analysis::Mappings::get ();
      41                 :     1985734 :   TypeCheckContext *context = TypeCheckContext::get ();
      42                 :             : 
      43                 :     1985734 :   if (context->lookup_type (reference, result))
      44                 :             :     return true;
      45                 :             : 
      46                 :       14182 :   if (context->query_in_progress (reference))
      47                 :             :     return false;
      48                 :             : 
      49                 :       11171 :   context->insert_query (reference);
      50                 :             : 
      51                 :       11171 :   std::pair<HIR::Enum *, HIR::EnumItem *> enum_candidiate
      52                 :       11171 :     = mappings.lookup_hir_enumitem (reference);
      53                 :       22342 :   bool enum_candidiate_ok
      54                 :       11171 :     = enum_candidiate.first != nullptr && enum_candidiate.second != nullptr;
      55                 :       11171 :   if (enum_candidiate_ok)
      56                 :             :     {
      57                 :        4234 :       HIR::Enum *parent = enum_candidiate.first;
      58                 :        4234 :       HIR::EnumItem *enum_item = enum_candidiate.second;
      59                 :        4234 :       rust_debug_loc (enum_item->get_locus (), "resolved item {%u} to",
      60                 :             :                       reference);
      61                 :             : 
      62                 :        4234 :       *result = TypeCheckItem::Resolve (*parent);
      63                 :             : 
      64                 :        4234 :       context->query_completed (reference);
      65                 :        4234 :       return true;
      66                 :             :     }
      67                 :             : 
      68                 :        6937 :   if (auto item = mappings.lookup_hir_item (reference))
      69                 :             :     {
      70                 :        1000 :       rust_debug_loc (item.value ()->get_locus (), "resolved item {%u} to",
      71                 :             :                       reference);
      72                 :        1000 :       *result = TypeCheckItem::Resolve (*item.value ());
      73                 :        1000 :       context->query_completed (reference);
      74                 :        1000 :       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                 :     1886831 : types_compatable (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
     155                 :             :                   location_t unify_locus, bool emit_errors, bool check_bounds)
     156                 :             : {
     157                 :     1886831 :   TyTy::BaseType *result
     158                 :     1886831 :     = unify_site_and (UNKNOWN_HIRID, lhs, rhs, unify_locus, emit_errors,
     159                 :             :                       false /*commit*/, true /*infer*/, true /*cleanup*/,
     160                 :             :                       check_bounds);
     161                 :     1886831 :   return result->get_kind () != TyTy::TypeKind::ERROR;
     162                 :             : }
     163                 :             : 
     164                 :             : TyTy::BaseType *
     165                 :       28980 : unify_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
     166                 :             :             location_t unify_locus)
     167                 :             : {
     168                 :       28980 :   TyTy::BaseType *expected = lhs.get_ty ();
     169                 :       28980 :   TyTy::BaseType *expr = rhs.get_ty ();
     170                 :             : 
     171                 :       28980 :   rust_debug ("unify_site id={%u} expected={%s} expr={%s}", id,
     172                 :             :               expected->debug_str ().c_str (), expr->debug_str ().c_str ());
     173                 :             : 
     174                 :       28980 :   std::vector<UnifyRules::CommitSite> commits;
     175                 :       28980 :   std::vector<UnifyRules::InferenceSite> infers;
     176                 :       28980 :   return UnifyRules::Resolve (lhs, rhs, unify_locus, true /*commit*/,
     177                 :             :                               true /*emit_error*/, false /*infer*/,
     178                 :       28980 :                               true /*check_bounds*/, commits, infers);
     179                 :       28980 : }
     180                 :             : 
     181                 :             : TyTy::BaseType *
     182                 :     2008492 : 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                 :     2008492 :   TypeCheckContext &context = *TypeCheckContext::get ();
     187                 :             : 
     188                 :     2008492 :   TyTy::BaseType *expected = lhs.get_ty ();
     189                 :     2008492 :   TyTy::BaseType *expr = rhs.get_ty ();
     190                 :             : 
     191                 :     7681919 :   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                 :     4016984 :                   expected->debug_str ().c_str (), expr->debug_str ().c_str ());
     198                 :             : 
     199                 :     2008492 :   std::vector<UnifyRules::CommitSite> commits;
     200                 :     2008492 :   std::vector<UnifyRules::InferenceSite> infers;
     201                 :     2008492 :   TyTy::BaseType *result
     202                 :     2008492 :     = UnifyRules::Resolve (lhs, rhs, unify_locus, false /*commit inline*/,
     203                 :             :                            emit_errors, implicit_infer_vars, check_bounds,
     204                 :             :                            commits, infers);
     205                 :     2008492 :   bool ok = result->get_kind () != TyTy::TypeKind::ERROR;
     206                 :             : 
     207                 :     3587068 :   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                 :     4016984 :                   id == UNKNOWN_HIRID ? 0 : id, expected->debug_str ().c_str (),
     213                 :     2008492 :                   expr->debug_str ().c_str ());
     214                 :             : 
     215                 :     2008492 :   if (ok && commit_if_ok)
     216                 :             :     {
     217                 :      195907 :       for (auto &c : commits)
     218                 :             :         {
     219                 :      115218 :           UnifyRules::commit (c.lhs, c.rhs, c.resolved);
     220                 :             :         }
     221                 :             :     }
     222                 :     1927803 :   else if (cleanup)
     223                 :             :     {
     224                 :     2012298 :       for (auto &i : infers)
     225                 :             :         {
     226                 :       84975 :           if (i.param != nullptr)
     227                 :             :             {
     228                 :       84926 :               i.param->set_ref (i.pref);
     229                 :       84926 :               i.param->set_ty_ref (i.ptyref);
     230                 :             :             }
     231                 :             : 
     232                 :             :           // remove the inference variable
     233                 :       84975 :           context.clear_type (i.infer);
     234                 :             :           // FIXME: Don't delete - result might point to this
     235                 :             :           // delete i.infer;
     236                 :             :         }
     237                 :             :     }
     238                 :     2008492 :   return result;
     239                 :     2008492 : }
     240                 :             : 
     241                 :             : TyTy::BaseType *
     242                 :       38183 : coercion_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
     243                 :             :                location_t locus)
     244                 :             : {
     245                 :       38183 :   TyTy::BaseType *expected = lhs.get_ty ();
     246                 :       38183 :   TyTy::BaseType *expr = rhs.get_ty ();
     247                 :             : 
     248                 :       38183 :   rust_debug ("coercion_site id={%u} expected={%s} expr={%s}", id,
     249                 :             :               expected->debug_str ().c_str (), expr->debug_str ().c_str ());
     250                 :             : 
     251                 :       38183 :   auto context = TypeCheckContext::get ();
     252                 :       38183 :   if (expected->get_kind () == TyTy::TypeKind::ERROR
     253                 :       38183 :       || expr->get_kind () == TyTy::TypeKind::ERROR)
     254                 :          21 :     return expr;
     255                 :             : 
     256                 :             :   // can we autoderef it?
     257                 :       38162 :   auto result = TypeCoercionRules::Coerce (expr, expected, locus,
     258                 :       38162 :                                            true /*allow-autodref*/);
     259                 :             : 
     260                 :             :   // the result needs to be unified
     261                 :       38162 :   TyTy::BaseType *receiver = expr;
     262                 :       38162 :   if (!result.is_error ())
     263                 :             :     {
     264                 :       38105 :       receiver = result.tyty;
     265                 :             :     }
     266                 :             : 
     267                 :       38162 :   rust_debug ("coerce_default_unify(a={%s}, b={%s})",
     268                 :             :               receiver->debug_str ().c_str (), expected->debug_str ().c_str ());
     269                 :       38162 :   TyTy::BaseType *coerced
     270                 :       38162 :     = unify_site_and (id, lhs,
     271                 :       38162 :                       TyTy::TyWithLocation (receiver, rhs.get_locus ()), locus,
     272                 :             :                       true /*emit_error*/, true /*commit*/, true /*infer*/,
     273                 :             :                       true /*cleanup*/);
     274                 :       38162 :   context->insert_autoderef_mappings (id, std::move (result.adjustments));
     275                 :       38162 :   return coerced;
     276                 :       38162 : }
     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                 :        5166 : cast_site (HirId id, TyTy::TyWithLocation from, TyTy::TyWithLocation to,
     298                 :             :            location_t cast_locus)
     299                 :             : {
     300                 :        5166 :   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                 :        5166 :   auto context = TypeCheckContext::get ();
     305                 :        5166 :   if (from.get_ty ()->get_kind () == TyTy::TypeKind::ERROR
     306                 :        5166 :       || to.get_ty ()->get_kind () == TyTy::TypeKind::ERROR)
     307                 :             :     return to.get_ty ();
     308                 :             : 
     309                 :             :   // do the cast
     310                 :        5166 :   auto result = TypeCastRules::resolve (cast_locus, from, to);
     311                 :             : 
     312                 :             :   // we assume error has already been emitted
     313                 :        5166 :   if (result.is_error ())
     314                 :             :     return to.get_ty ();
     315                 :             : 
     316                 :             :   // the result needs to be unified
     317                 :        5150 :   TyTy::BaseType *casted_result = result.tyty;
     318                 :        5150 :   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                 :        5150 :   TyTy::BaseType *casted
     323                 :        5150 :     = unify_site (id, to,
     324                 :        5150 :                   TyTy::TyWithLocation (casted_result, from.get_locus ()),
     325                 :             :                   cast_locus);
     326                 :        5150 :   context->insert_cast_autoderef_mappings (id, std::move (result.adjustments));
     327                 :        5150 :   return casted;
     328                 :        5166 : }
     329                 :             : 
     330                 :             : AssociatedImplTrait *
     331                 :        8548 : lookup_associated_impl_block (const TyTy::TypeBoundPredicate &bound,
     332                 :             :                               TyTy::BaseType *binding, bool *ambigious)
     333                 :             : {
     334                 :        8548 :   auto context = TypeCheckContext::get ();
     335                 :             : 
     336                 :             :   // setup any associated type mappings for the specified bonds and this
     337                 :             :   // type
     338                 :        8548 :   auto candidates = TypeBoundsProbe::Probe (binding);
     339                 :        8548 :   std::vector<AssociatedImplTrait *> associated_impl_traits;
     340                 :       49744 :   for (auto &probed_bound : candidates)
     341                 :             :     {
     342                 :       41196 :       HIR::ImplBlock *associated_impl = probed_bound.second;
     343                 :             : 
     344                 :       41196 :       HirId impl_block_id = associated_impl->get_mappings ().get_hirid ();
     345                 :       41196 :       AssociatedImplTrait *associated = nullptr;
     346                 :       41196 :       bool found_impl_trait
     347                 :       41196 :         = context->lookup_associated_trait_impl (impl_block_id, &associated);
     348                 :       41196 :       if (found_impl_trait)
     349                 :             :         {
     350                 :             :           // compare the bounds from here i think is what we can do:
     351                 :       20529 :           if (bound.is_equal (associated->get_predicate ()))
     352                 :             :             {
     353                 :        2129 :               associated_impl_traits.push_back (associated);
     354                 :             :             }
     355                 :             :         }
     356                 :             :     }
     357                 :             : 
     358                 :        8548 :   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                 :        2107 :   bool is_infer_var = binding->get_kind () == TyTy::TypeKind::INFER;
     381                 :        2107 :   bool is_integer_infervar
     382                 :             :     = is_infer_var
     383                 :        2107 :       && static_cast<const TyTy::InferType *> (binding)->get_infer_kind ()
     384                 :        2177 :            == 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                 :        2107 :            == TyTy::InferType::InferTypeKind::FLOAT;
     389                 :             : 
     390                 :        2107 :   AssociatedImplTrait *associate_impl_trait = nullptr;
     391                 :        2107 :   if (associated_impl_traits.size () == 1)
     392                 :             :     {
     393                 :             :       // just go for it
     394                 :        2085 :       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                 :        2107 :   if (associate_impl_trait == nullptr && ambigious != nullptr)
     430                 :             :     {
     431                 :          22 :       *ambigious = true;
     432                 :             :     }
     433                 :             : 
     434                 :             :   return associate_impl_trait;
     435                 :        8548 : }
     436                 :             : 
     437                 :             : } // namespace Resolver
     438                 :             : } // namespace Rust
        

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