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