LCOV - code coverage report
Current view: top level - gcc/rust/typecheck - rust-type-util.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 89.3 % 178 159
Test Date: 2024-12-21 13:15:12 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-2024 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-casts.h"
      26                 :             : #include "rust-unify.h"
      27                 :             : #include "rust-coercion.h"
      28                 :             : #include "rust-hir-type-bounds.h"
      29                 :             : 
      30                 :             : namespace Rust {
      31                 :             : namespace Resolver {
      32                 :             : 
      33                 :             : bool
      34                 :      242527 : query_type (HirId reference, TyTy::BaseType **result)
      35                 :             : {
      36                 :      242527 :   Analysis::Mappings *mappings = Analysis::Mappings::get ();
      37                 :      242527 :   TypeCheckContext *context = TypeCheckContext::get ();
      38                 :             : 
      39                 :      242527 :   if (context->query_in_progress (reference))
      40                 :             :     return false;
      41                 :             : 
      42                 :      240962 :   if (context->lookup_type (reference, result))
      43                 :             :     return true;
      44                 :             : 
      45                 :        3014 :   context->insert_query (reference);
      46                 :             : 
      47                 :        3014 :   std::pair<HIR::Enum *, HIR::EnumItem *> enum_candidiate
      48                 :        3014 :     = mappings->lookup_hir_enumitem (reference);
      49                 :        6028 :   bool enum_candidiate_ok
      50                 :        3014 :     = enum_candidiate.first != nullptr && enum_candidiate.second != nullptr;
      51                 :        3014 :   if (enum_candidiate_ok)
      52                 :             :     {
      53                 :         660 :       HIR::Enum *parent = enum_candidiate.first;
      54                 :         660 :       HIR::EnumItem *enum_item = enum_candidiate.second;
      55                 :         660 :       rust_debug_loc (enum_item->get_locus (), "resolved item {%u} to",
      56                 :             :                       reference);
      57                 :             : 
      58                 :         660 :       *result = TypeCheckItem::Resolve (*parent);
      59                 :             : 
      60                 :         660 :       context->query_completed (reference);
      61                 :         660 :       return true;
      62                 :             :     }
      63                 :             : 
      64                 :        2354 :   HIR::Item *item = mappings->lookup_hir_item (reference);
      65                 :        2354 :   if (item != nullptr)
      66                 :             :     {
      67                 :         368 :       rust_debug_loc (item->get_locus (), "resolved item {%u} to", reference);
      68                 :         368 :       *result = TypeCheckItem::Resolve (*item);
      69                 :         368 :       context->query_completed (reference);
      70                 :         368 :       return true;
      71                 :             :     }
      72                 :             : 
      73                 :        1986 :   HirId parent_impl_id = UNKNOWN_HIRID;
      74                 :        1986 :   HIR::ImplItem *impl_item
      75                 :        1986 :     = mappings->lookup_hir_implitem (reference, &parent_impl_id);
      76                 :        1986 :   if (impl_item != nullptr)
      77                 :             :     {
      78                 :        1392 :       HIR::ImplBlock *impl_block
      79                 :        1392 :         = mappings->lookup_hir_impl_block (parent_impl_id);
      80                 :        1392 :       rust_assert (impl_block != nullptr);
      81                 :             : 
      82                 :             :       // found an impl item
      83                 :        1392 :       rust_debug_loc (impl_item->get_locus (), "resolved impl-item {%u} to",
      84                 :             :                       reference);
      85                 :             : 
      86                 :        1392 :       *result = TypeCheckItem::ResolveImplItem (*impl_block, *impl_item);
      87                 :        1392 :       context->query_completed (reference);
      88                 :        1392 :       return true;
      89                 :             :     }
      90                 :             : 
      91                 :             :   // is it an impl_type?
      92                 :         594 :   HIR::ImplBlock *impl_block_by_type = nullptr;
      93                 :         594 :   bool found_impl_block_type
      94                 :         594 :     = mappings->lookup_impl_block_type (reference, &impl_block_by_type);
      95                 :         594 :   if (found_impl_block_type)
      96                 :             :     {
      97                 :         581 :       *result = TypeCheckItem::ResolveImplBlockSelf (*impl_block_by_type);
      98                 :         581 :       context->query_completed (reference);
      99                 :         581 :       return true;
     100                 :             :     }
     101                 :             : 
     102                 :             :   // is it an extern item?
     103                 :          13 :   HirId parent_extern_block_id = UNKNOWN_HIRID;
     104                 :          13 :   HIR::ExternalItem *extern_item
     105                 :          13 :     = mappings->lookup_hir_extern_item (reference, &parent_extern_block_id);
     106                 :          13 :   if (extern_item != nullptr)
     107                 :             :     {
     108                 :          12 :       HIR::ExternBlock *block
     109                 :          12 :         = mappings->lookup_hir_extern_block (parent_extern_block_id);
     110                 :          12 :       rust_assert (block != nullptr);
     111                 :             : 
     112                 :          12 :       *result = TypeCheckTopLevelExternItem::Resolve (extern_item, *block);
     113                 :          12 :       context->query_completed (reference);
     114                 :          12 :       return true;
     115                 :             :     }
     116                 :             : 
     117                 :             :   // more?
     118                 :           1 :   location_t possible_locus = mappings->lookup_location (reference);
     119                 :           1 :   rust_debug_loc (possible_locus, "query system failed to resolve: [%u]",
     120                 :             :                   reference);
     121                 :           1 :   context->query_completed (reference);
     122                 :             : 
     123                 :           1 :   return false;
     124                 :             : }
     125                 :             : 
     126                 :             : bool
     127                 :        2500 : types_compatable (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
     128                 :             :                   location_t unify_locus, bool emit_errors)
     129                 :             : {
     130                 :        2500 :   TyTy::BaseType *result
     131                 :        2500 :     = unify_site_and (UNKNOWN_HIRID, lhs, rhs, unify_locus, emit_errors,
     132                 :             :                       false /*commit*/, true /*infer*/, true /*cleanup*/);
     133                 :        2500 :   return result->get_kind () != TyTy::TypeKind::ERROR;
     134                 :             : }
     135                 :             : 
     136                 :             : TyTy::BaseType *
     137                 :       68088 : unify_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
     138                 :             :             location_t unify_locus)
     139                 :             : {
     140                 :       68088 :   TyTy::BaseType *expected = lhs.get_ty ();
     141                 :       68088 :   TyTy::BaseType *expr = rhs.get_ty ();
     142                 :             : 
     143                 :       68088 :   rust_debug ("unify_site id={%u} expected={%s} expr={%s}", id,
     144                 :             :               expected->debug_str ().c_str (), expr->debug_str ().c_str ());
     145                 :             : 
     146                 :       68088 :   std::vector<UnifyRules::CommitSite> commits;
     147                 :       68088 :   std::vector<UnifyRules::InferenceSite> infers;
     148                 :       68088 :   return UnifyRules::Resolve (lhs, rhs, unify_locus, true /*commit*/,
     149                 :             :                               true /*emit_error*/, false /*infer*/, commits,
     150                 :       68088 :                               infers);
     151                 :       68088 : }
     152                 :             : 
     153                 :             : TyTy::BaseType *
     154                 :       35710 : unify_site_and (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
     155                 :             :                 location_t unify_locus, bool emit_errors, bool commit_if_ok,
     156                 :             :                 bool implicit_infer_vars, bool cleanup)
     157                 :             : {
     158                 :       35710 :   TypeCheckContext &context = *TypeCheckContext::get ();
     159                 :             : 
     160                 :       35710 :   TyTy::BaseType *expected = lhs.get_ty ();
     161                 :       35710 :   TyTy::BaseType *expr = rhs.get_ty ();
     162                 :             : 
     163                 :       74037 :   rust_debug (
     164                 :             :     "unify_site_and commit %s infer %s id={%u} expected={%s} expr={%s}",
     165                 :             :     commit_if_ok ? "true" : "false", implicit_infer_vars ? "true" : "false", id,
     166                 :             :     expected->debug_str ().c_str (), expr->debug_str ().c_str ());
     167                 :             : 
     168                 :       35710 :   std::vector<UnifyRules::CommitSite> commits;
     169                 :       35710 :   std::vector<UnifyRules::InferenceSite> infers;
     170                 :       35710 :   TyTy::BaseType *result
     171                 :       35710 :     = UnifyRules::Resolve (lhs, rhs, unify_locus, false /*commit inline*/,
     172                 :             :                            emit_errors, implicit_infer_vars, commits, infers);
     173                 :       35710 :   bool ok = result->get_kind () != TyTy::TypeKind::ERROR;
     174                 :       35710 :   if (ok && commit_if_ok)
     175                 :             :     {
     176                 :       54619 :       for (auto &c : commits)
     177                 :             :         {
     178                 :       31662 :           UnifyRules::commit (c.lhs, c.rhs, c.resolved);
     179                 :             :         }
     180                 :             :     }
     181                 :       12753 :   else if (cleanup)
     182                 :             :     {
     183                 :             :       // FIXME
     184                 :             :       // reset the get_next_hir_id
     185                 :             : 
     186                 :       13993 :       for (auto &i : infers)
     187                 :             :         {
     188                 :        1270 :           i.param->set_ref (i.pref);
     189                 :        1270 :           i.param->set_ty_ref (i.ptyref);
     190                 :             : 
     191                 :             :           // remove the inference variable
     192                 :        1270 :           context.clear_type (i.infer);
     193                 :        1270 :           delete i.infer;
     194                 :             :         }
     195                 :             :     }
     196                 :       35710 :   return result;
     197                 :       35710 : }
     198                 :             : 
     199                 :             : TyTy::BaseType *
     200                 :       21257 : coercion_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
     201                 :             :                location_t locus)
     202                 :             : {
     203                 :       21257 :   TyTy::BaseType *expected = lhs.get_ty ();
     204                 :       21257 :   TyTy::BaseType *expr = rhs.get_ty ();
     205                 :             : 
     206                 :       21257 :   rust_debug ("coercion_site id={%u} expected={%s} expr={%s}", id,
     207                 :             :               expected->debug_str ().c_str (), expr->debug_str ().c_str ());
     208                 :             : 
     209                 :       21257 :   auto context = TypeCheckContext::get ();
     210                 :       21257 :   if (expected->get_kind () == TyTy::TypeKind::ERROR
     211                 :       21257 :       || expr->get_kind () == TyTy::TypeKind::ERROR)
     212                 :           8 :     return expr;
     213                 :             : 
     214                 :             :   // can we autoderef it?
     215                 :       21249 :   auto result = TypeCoercionRules::Coerce (expr, expected, locus,
     216                 :       21249 :                                            true /*allow-autodref*/);
     217                 :             : 
     218                 :             :   // the result needs to be unified
     219                 :       21249 :   TyTy::BaseType *receiver = expr;
     220                 :       21249 :   if (!result.is_error ())
     221                 :             :     {
     222                 :       21217 :       receiver = result.tyty;
     223                 :             :     }
     224                 :             : 
     225                 :       21249 :   rust_debug ("coerce_default_unify(a={%s}, b={%s})",
     226                 :             :               receiver->debug_str ().c_str (), expected->debug_str ().c_str ());
     227                 :       21249 :   TyTy::BaseType *coerced
     228                 :       21249 :     = unify_site (id, lhs, TyTy::TyWithLocation (receiver, rhs.get_locus ()),
     229                 :             :                   locus);
     230                 :       21249 :   context->insert_autoderef_mappings (id, std::move (result.adjustments));
     231                 :       21249 :   return coerced;
     232                 :       21249 : }
     233                 :             : 
     234                 :             : TyTy::BaseType *
     235                 :         289 : try_coercion (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
     236                 :             :               location_t locus)
     237                 :             : {
     238                 :         289 :   TyTy::BaseType *expected = lhs.get_ty ();
     239                 :         289 :   TyTy::BaseType *expr = rhs.get_ty ();
     240                 :             : 
     241                 :         289 :   rust_debug ("try_coercion_site id={%u} expected={%s} expr={%s}", id,
     242                 :             :               expected->debug_str ().c_str (), expr->debug_str ().c_str ());
     243                 :             : 
     244                 :         289 :   auto result = TypeCoercionRules::TryCoerce (expr, expected, locus,
     245                 :         289 :                                               true /*allow-autodref*/);
     246                 :         289 :   if (result.is_error ())
     247                 :          17 :     return new TyTy::ErrorType (id);
     248                 :             : 
     249                 :         272 :   return result.tyty;
     250                 :         289 : }
     251                 :             : 
     252                 :             : TyTy::BaseType *
     253                 :        3313 : cast_site (HirId id, TyTy::TyWithLocation from, TyTy::TyWithLocation to,
     254                 :             :            location_t cast_locus)
     255                 :             : {
     256                 :        3313 :   rust_debug ("cast_site id={%u} from={%s} to={%s}", id,
     257                 :             :               from.get_ty ()->debug_str ().c_str (),
     258                 :             :               to.get_ty ()->debug_str ().c_str ());
     259                 :             : 
     260                 :        3313 :   auto context = TypeCheckContext::get ();
     261                 :        3313 :   if (from.get_ty ()->get_kind () == TyTy::TypeKind::ERROR
     262                 :        3313 :       || to.get_ty ()->get_kind () == TyTy::TypeKind::ERROR)
     263                 :             :     return to.get_ty ();
     264                 :             : 
     265                 :             :   // do the cast
     266                 :        3313 :   auto result = TypeCastRules::resolve (cast_locus, from, to);
     267                 :             : 
     268                 :             :   // we assume error has already been emitted
     269                 :        3313 :   if (result.is_error ())
     270                 :             :     return to.get_ty ();
     271                 :             : 
     272                 :             :   // the result needs to be unified
     273                 :        3297 :   TyTy::BaseType *casted_result = result.tyty;
     274                 :        3297 :   rust_debug ("cast_default_unify(a={%s}, b={%s})",
     275                 :             :               casted_result->debug_str ().c_str (),
     276                 :             :               to.get_ty ()->debug_str ().c_str ());
     277                 :             : 
     278                 :        3297 :   TyTy::BaseType *casted
     279                 :        3297 :     = unify_site (id, to,
     280                 :        3297 :                   TyTy::TyWithLocation (casted_result, from.get_locus ()),
     281                 :             :                   cast_locus);
     282                 :        3297 :   context->insert_cast_autoderef_mappings (id, std::move (result.adjustments));
     283                 :        3297 :   return casted;
     284                 :        3313 : }
     285                 :             : 
     286                 :             : AssociatedImplTrait *
     287                 :        4622 : lookup_associated_impl_block (const TyTy::TypeBoundPredicate &bound,
     288                 :             :                               const TyTy::BaseType *binding, bool *ambigious)
     289                 :             : {
     290                 :        4622 :   auto context = TypeCheckContext::get ();
     291                 :             : 
     292                 :             :   // setup any associated type mappings for the specified bonds and this
     293                 :             :   // type
     294                 :        4622 :   auto candidates = TypeBoundsProbe::Probe (binding);
     295                 :        4622 :   std::vector<AssociatedImplTrait *> associated_impl_traits;
     296                 :       20005 :   for (auto &probed_bound : candidates)
     297                 :             :     {
     298                 :       15383 :       HIR::ImplBlock *associated_impl = probed_bound.second;
     299                 :             : 
     300                 :       15383 :       HirId impl_block_id = associated_impl->get_mappings ().get_hirid ();
     301                 :       15383 :       AssociatedImplTrait *associated = nullptr;
     302                 :       15383 :       bool found_impl_trait
     303                 :       15383 :         = context->lookup_associated_trait_impl (impl_block_id, &associated);
     304                 :       15383 :       if (found_impl_trait)
     305                 :             :         {
     306                 :             :           // compare the bounds from here i think is what we can do:
     307                 :        6983 :           if (bound.is_equal (associated->get_predicate ()))
     308                 :             :             {
     309                 :         910 :               associated_impl_traits.push_back (associated);
     310                 :             :             }
     311                 :             :         }
     312                 :             :     }
     313                 :             : 
     314                 :        4622 :   if (associated_impl_traits.empty ())
     315                 :             :     return nullptr;
     316                 :             : 
     317                 :             :   // This code is important when you look at slices for example when
     318                 :             :   // you have a slice such as:
     319                 :             :   //
     320                 :             :   // let slice = &array[1..3]
     321                 :             :   //
     322                 :             :   // the higher ranked bounds will end up having an Index trait
     323                 :             :   // implementation for Range<usize> so we need this code to resolve
     324                 :             :   // that we have an integer inference variable that needs to become
     325                 :             :   // a usize
     326                 :             :   //
     327                 :             :   // The other complicated issue is that we might have an intrinsic
     328                 :             :   // which requires the :Clone or Copy bound but the libcore adds
     329                 :             :   // implementations for all the integral types so when there are
     330                 :             :   // multiple candidates we need to resolve to the default
     331                 :             :   // implementation for that type otherwise its an error for
     332                 :             :   // ambiguous type bounds
     333                 :             : 
     334                 :             :   // if we have a non-general inference variable we need to be
     335                 :             :   // careful about the selection here
     336                 :         910 :   bool is_infer_var = binding->get_kind () == TyTy::TypeKind::INFER;
     337                 :         910 :   bool is_integer_infervar
     338                 :             :     = is_infer_var
     339                 :         910 :       && static_cast<const TyTy::InferType *> (binding)->get_infer_kind ()
     340                 :         939 :            == TyTy::InferType::InferTypeKind::INTEGRAL;
     341                 :          29 :   bool is_float_infervar
     342                 :             :     = is_infer_var
     343                 :          29 :       && static_cast<const TyTy::InferType *> (binding)->get_infer_kind ()
     344                 :         910 :            == TyTy::InferType::InferTypeKind::FLOAT;
     345                 :             : 
     346                 :         910 :   AssociatedImplTrait *associate_impl_trait = nullptr;
     347                 :         910 :   if (associated_impl_traits.size () == 1)
     348                 :             :     {
     349                 :             :       // just go for it
     350                 :         910 :       associate_impl_trait = associated_impl_traits.at (0);
     351                 :             :     }
     352                 :           0 :   else if (is_integer_infervar)
     353                 :             :     {
     354                 :           0 :       TyTy::BaseType *type = nullptr;
     355                 :           0 :       bool ok = context->lookup_builtin ("i32", &type);
     356                 :           0 :       rust_assert (ok);
     357                 :             : 
     358                 :           0 :       for (auto &impl : associated_impl_traits)
     359                 :             :         {
     360                 :           0 :           bool found = impl->get_self ()->is_equal (*type);
     361                 :           0 :           if (found)
     362                 :             :             {
     363                 :           0 :               associate_impl_trait = impl;
     364                 :           0 :               break;
     365                 :             :             }
     366                 :             :         }
     367                 :             :     }
     368                 :           0 :   else if (is_float_infervar)
     369                 :             :     {
     370                 :           0 :       TyTy::BaseType *type = nullptr;
     371                 :           0 :       bool ok = context->lookup_builtin ("f64", &type);
     372                 :           0 :       rust_assert (ok);
     373                 :             : 
     374                 :           0 :       for (auto &impl : associated_impl_traits)
     375                 :             :         {
     376                 :           0 :           bool found = impl->get_self ()->is_equal (*type);
     377                 :           0 :           if (found)
     378                 :             :             {
     379                 :           0 :               associate_impl_trait = impl;
     380                 :           0 :               break;
     381                 :             :             }
     382                 :             :         }
     383                 :             :     }
     384                 :             : 
     385                 :         910 :   if (associate_impl_trait == nullptr && ambigious != nullptr)
     386                 :             :     {
     387                 :           0 :       *ambigious = true;
     388                 :             :     }
     389                 :             : 
     390                 :             :   return associate_impl_trait;
     391                 :        4622 : }
     392                 :             : 
     393                 :             : } // namespace Resolver
     394                 :             : } // 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.