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