LCOV - code coverage report
Current view: top level - gcc/rust/typecheck - rust-hir-type-check-struct.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 91.0 % 222 202
Test Date: 2024-12-21 13:15:12 Functions: 100.0 % 7 7
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-hir-type-check.h"
      20                 :             : #include "rust-hir-type-check-expr.h"
      21                 :             : #include "rust-hir-type-check-struct-field.h"
      22                 :             : #include "rust-type-util.h"
      23                 :             : 
      24                 :             : namespace Rust {
      25                 :             : namespace Resolver {
      26                 :             : 
      27                 :         811 : TypeCheckStructExpr::TypeCheckStructExpr (HIR::Expr *e)
      28                 :             :   : TypeCheckBase (),
      29                 :         811 :     resolved (new TyTy::ErrorType (e->get_mappings ().get_hirid ())),
      30                 :         811 :     struct_path_resolved (nullptr),
      31                 :        1622 :     variant (&TyTy::VariantDef::get_error_node ())
      32                 :         811 : {}
      33                 :             : 
      34                 :             : TyTy::BaseType *
      35                 :         811 : TypeCheckStructExpr::Resolve (HIR::StructExprStructFields *expr)
      36                 :             : {
      37                 :         811 :   TypeCheckStructExpr resolver (expr);
      38                 :         811 :   resolver.resolve (*expr);
      39                 :        1620 :   return resolver.resolved;
      40                 :         810 : }
      41                 :             : 
      42                 :             : void
      43                 :         811 : TypeCheckStructExpr::resolve (HIR::StructExprStructFields &struct_expr)
      44                 :             : {
      45                 :         811 :   TyTy::BaseType *struct_path_ty
      46                 :         811 :     = TypeCheckExpr::Resolve (&struct_expr.get_struct_name ());
      47                 :         811 :   if (struct_path_ty->get_kind () != TyTy::TypeKind::ADT)
      48                 :             :     {
      49                 :           0 :       rust_error_at (struct_expr.get_struct_name ().get_locus (),
      50                 :             :                      "expected an ADT type for constructor");
      51                 :           3 :       return;
      52                 :             :     }
      53                 :             : 
      54                 :         811 :   struct_path_resolved = static_cast<TyTy::ADTType *> (struct_path_ty);
      55                 :         811 :   TyTy::ADTType *struct_def = struct_path_resolved;
      56                 :         811 :   if (struct_expr.has_struct_base ())
      57                 :             :     {
      58                 :          63 :       TyTy::BaseType *base_resolved
      59                 :          63 :         = TypeCheckExpr::Resolve (struct_expr.struct_base->base_struct.get ());
      60                 :          63 :       TyTy::BaseType *base_unify = unify_site (
      61                 :          63 :         struct_expr.struct_base->base_struct->get_mappings ().get_hirid (),
      62                 :          63 :         TyTy::TyWithLocation (struct_path_resolved),
      63                 :          63 :         TyTy::TyWithLocation (base_resolved),
      64                 :          63 :         struct_expr.struct_base->base_struct->get_locus ());
      65                 :             : 
      66                 :          63 :       if (base_unify->get_kind () != struct_path_ty->get_kind ())
      67                 :             :         {
      68                 :           0 :           rust_fatal_error (struct_expr.struct_base->base_struct->get_locus (),
      69                 :             :                             "incompatible types for base struct reference");
      70                 :             :           return;
      71                 :             :         }
      72                 :             : 
      73                 :             :       struct_def = static_cast<TyTy::ADTType *> (base_unify);
      74                 :             :     }
      75                 :             : 
      76                 :             :   // figure out the variant
      77                 :         811 :   if (struct_path_resolved->is_enum ())
      78                 :             :     {
      79                 :             :       // lookup variant id
      80                 :          28 :       HirId variant_id;
      81                 :          28 :       bool ok = context->lookup_variant_definition (
      82                 :          28 :         struct_expr.get_struct_name ().get_mappings ().get_hirid (),
      83                 :             :         &variant_id);
      84                 :          28 :       rust_assert (ok);
      85                 :             : 
      86                 :          28 :       ok = struct_path_resolved->lookup_variant_by_id (variant_id, &variant);
      87                 :          28 :       rust_assert (ok);
      88                 :             :     }
      89                 :             :   else
      90                 :             :     {
      91                 :         783 :       rust_assert (struct_path_resolved->number_of_variants () == 1);
      92                 :         783 :       variant = struct_path_resolved->get_variants ().at (0);
      93                 :             :     }
      94                 :             : 
      95                 :         811 :   std::vector<TyTy::StructFieldType *> infered_fields;
      96                 :         811 :   bool ok = true;
      97                 :             : 
      98                 :        2344 :   for (auto &field : struct_expr.get_fields ())
      99                 :             :     {
     100                 :        1535 :       resolved_field_value_expr = nullptr;
     101                 :             : 
     102                 :        1535 :       switch (field->get_kind ())
     103                 :             :         {
     104                 :         211 :         case HIR::StructExprField::StructExprFieldKind::IDENTIFIER:
     105                 :         211 :           ok = visit (
     106                 :         211 :             static_cast<HIR::StructExprFieldIdentifier &> (*field.get ()));
     107                 :         211 :           break;
     108                 :             : 
     109                 :        1281 :         case HIR::StructExprField::StructExprFieldKind::IDENTIFIER_VALUE:
     110                 :        1281 :           ok = visit (
     111                 :        1281 :             static_cast<HIR::StructExprFieldIdentifierValue &> (*field.get ()));
     112                 :        1281 :           break;
     113                 :             : 
     114                 :          43 :         case HIR::StructExprField::StructExprFieldKind::INDEX_VALUE:
     115                 :          43 :           ok = visit (
     116                 :          43 :             static_cast<HIR::StructExprFieldIndexValue &> (*field.get ()));
     117                 :          43 :           break;
     118                 :             :         }
     119                 :             : 
     120                 :        1535 :       if (!ok)
     121                 :             :         {
     122                 :           3 :           return;
     123                 :             :         }
     124                 :             : 
     125                 :        1534 :       if (resolved_field_value_expr == nullptr)
     126                 :             :         {
     127                 :           1 :           rust_fatal_error (field->get_locus (),
     128                 :             :                             "failed to resolve type for field");
     129                 :             :           ok = false;
     130                 :             :           break;
     131                 :             :         }
     132                 :             : 
     133                 :        1533 :       context->insert_type (field->get_mappings (), resolved_field_value_expr);
     134                 :             :     }
     135                 :             : 
     136                 :             :   // something failed setting up the fields
     137                 :         809 :   if (!ok)
     138                 :             :     {
     139                 :             :       rust_error_at (struct_expr.get_locus (),
     140                 :             :                      "constructor type resolution failure");
     141                 :             :       return;
     142                 :             :     }
     143                 :             : 
     144                 :             :   // check the arguments are all assigned and fix up the ordering
     145                 :        1616 :   std::vector<std::string> missing_field_names;
     146                 :        3286 :   for (auto &field : variant->get_fields ())
     147                 :             :     {
     148                 :        2477 :       auto it = fields_assigned.find (field->get_name ());
     149                 :        2477 :       if (it == fields_assigned.end ())
     150                 :             :         {
     151                 :         945 :           missing_field_names.push_back (field->get_name ());
     152                 :             :         }
     153                 :             :     }
     154                 :         809 :   if (!missing_field_names.empty ())
     155                 :             :     {
     156                 :         200 :       if (struct_def->is_union ())
     157                 :             :         {
     158                 :         142 :           if (fields_assigned.size () != 1 || struct_expr.has_struct_base ())
     159                 :             :             {
     160                 :           0 :               rust_error_at (
     161                 :             :                 struct_expr.get_locus (),
     162                 :             :                 "union must have exactly one field variant assigned");
     163                 :           2 :               return;
     164                 :             :             }
     165                 :             :         }
     166                 :          58 :       else if (!struct_expr.has_struct_base ())
     167                 :             :         {
     168                 :           2 :           Error missing_fields_error
     169                 :             :             = make_missing_field_error (struct_expr.get_locus (),
     170                 :             :                                         missing_field_names,
     171                 :           2 :                                         struct_path_ty->get_name ());
     172                 :             :           // We might want to return or handle these in the future emit for now.
     173                 :           2 :           missing_fields_error.emit ();
     174                 :           2 :           return;
     175                 :           2 :         }
     176                 :             :       else
     177                 :             :         {
     178                 :             :           // we have a struct base to assign the missing fields from.
     179                 :             :           // the missing fields can be implicit FieldAccessExprs for the value
     180                 :          56 :           std::set<std::string> missing_fields;
     181                 :         714 :           for (auto &field : variant->get_fields ())
     182                 :             :             {
     183                 :         658 :               auto it = fields_assigned.find (field->get_name ());
     184                 :         658 :               if (it == fields_assigned.end ())
     185                 :         616 :                 missing_fields.insert (field->get_name ());
     186                 :             :             }
     187                 :             : 
     188                 :             :           // we can generate FieldAccessExpr or TupleAccessExpr for the
     189                 :             :           // values of the missing fields.
     190                 :         672 :           for (auto &missing : missing_fields)
     191                 :             :             {
     192                 :         616 :               HIR::Expr *receiver
     193                 :         616 :                 = struct_expr.struct_base->base_struct->clone_expr_impl ();
     194                 :             : 
     195                 :         616 :               HIR::StructExprField *implicit_field = nullptr;
     196                 :             : 
     197                 :         616 :               AST::AttrVec outer_attribs;
     198                 :         616 :               auto crate_num = mappings->get_current_crate ();
     199                 :         616 :               Analysis::NodeMapping mapping (
     200                 :             :                 crate_num,
     201                 :         616 :                 struct_expr.struct_base->base_struct->get_mappings ()
     202                 :             :                   .get_nodeid (),
     203                 :         616 :                 mappings->get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID);
     204                 :             : 
     205                 :         616 :               HIR::Expr *field_value = new HIR::FieldAccessExpr (
     206                 :        1232 :                 mapping, std::unique_ptr<HIR::Expr> (receiver), missing,
     207                 :             :                 std::move (outer_attribs),
     208                 :        1232 :                 struct_expr.struct_base->base_struct->get_locus ());
     209                 :             : 
     210                 :         616 :               implicit_field = new HIR::StructExprFieldIdentifierValue (
     211                 :         616 :                 mapping, missing, std::unique_ptr<HIR::Expr> (field_value),
     212                 :        1232 :                 struct_expr.struct_base->base_struct->get_locus ());
     213                 :             : 
     214                 :         616 :               size_t field_index;
     215                 :         616 :               bool ok = variant->lookup_field (missing, nullptr, &field_index);
     216                 :         616 :               rust_assert (ok);
     217                 :             : 
     218                 :         616 :               adtFieldIndexToField[field_index] = implicit_field;
     219                 :         616 :               struct_expr.get_fields ().push_back (
     220                 :         616 :                 std::unique_ptr<HIR::StructExprField> (implicit_field));
     221                 :         616 :             }
     222                 :          56 :         }
     223                 :             :     }
     224                 :             : 
     225                 :         807 :   if (struct_def->is_union ())
     226                 :             :     {
     227                 :             :       // There is exactly one field in this constructor, we need to
     228                 :             :       // figure out the field index to make sure we initialize the
     229                 :             :       // right union field.
     230                 :         268 :       for (size_t i = 0; i < adtFieldIndexToField.size (); i++)
     231                 :             :         {
     232                 :         268 :           if (adtFieldIndexToField[i])
     233                 :             :             {
     234                 :         149 :               struct_expr.union_index = i;
     235                 :         149 :               break;
     236                 :             :             }
     237                 :             :         }
     238                 :         149 :       rust_assert (struct_expr.union_index != -1);
     239                 :             :     }
     240                 :             :   else
     241                 :             :     {
     242                 :             :       // everything is ok, now we need to ensure all field values are ordered
     243                 :             :       // correctly. The GIMPLE backend uses a simple algorithm that assumes each
     244                 :             :       // assigned field in the constructor is in the same order as the field in
     245                 :             :       // the type
     246                 :        2654 :       for (auto &field : struct_expr.get_fields ())
     247                 :        1996 :         field.release ();
     248                 :             : 
     249                 :         658 :       std::vector<std::unique_ptr<HIR::StructExprField> > ordered_fields;
     250                 :        2654 :       for (size_t i = 0; i < adtFieldIndexToField.size (); i++)
     251                 :             :         {
     252                 :        3992 :           ordered_fields.push_back (
     253                 :        1996 :             std::unique_ptr<HIR::StructExprField> (adtFieldIndexToField[i]));
     254                 :             :         }
     255                 :         658 :       struct_expr.set_fields_as_owner (std::move (ordered_fields));
     256                 :         658 :     }
     257                 :             : 
     258                 :         807 :   resolved = struct_def;
     259                 :         810 : }
     260                 :             : 
     261                 :             : bool
     262                 :        1281 : TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifierValue &field)
     263                 :             : {
     264                 :        1281 :   size_t field_index;
     265                 :        1281 :   TyTy::StructFieldType *field_type;
     266                 :        1281 :   bool ok = variant->lookup_field (field.field_name.as_string (), &field_type,
     267                 :             :                                    &field_index);
     268                 :        1281 :   if (!ok)
     269                 :             :     {
     270                 :           0 :       rust_error_at (field.get_locus (), "unknown field");
     271                 :           0 :       return true;
     272                 :             :     }
     273                 :             : 
     274                 :        1281 :   auto it = adtFieldIndexToField.find (field_index);
     275                 :        1281 :   if (it != adtFieldIndexToField.end ())
     276                 :             :     {
     277                 :           1 :       rich_location repeat_location (line_table, field.get_locus ());
     278                 :           1 :       auto prev_field_locus = it->second->get_locus ();
     279                 :           1 :       repeat_location.add_range (prev_field_locus);
     280                 :             : 
     281                 :           1 :       rust_error_at (repeat_location, ErrorCode::E0062,
     282                 :             :                      "field %qs specified more than once",
     283                 :           1 :                      field.field_name.as_string ().c_str ());
     284                 :           1 :       return false;
     285                 :           1 :     }
     286                 :             : 
     287                 :        1280 :   TyTy::BaseType *value = TypeCheckExpr::Resolve (field.get_value ().get ());
     288                 :        1280 :   location_t value_locus = field.get_value ()->get_locus ();
     289                 :             : 
     290                 :        1280 :   HirId coercion_site_id = field.get_mappings ().get_hirid ();
     291                 :        1280 :   resolved_field_value_expr
     292                 :        2560 :     = coercion_site (coercion_site_id,
     293                 :             :                      TyTy::TyWithLocation (field_type->get_field_type (),
     294                 :        1280 :                                            field_type->get_locus ()),
     295                 :        1280 :                      TyTy::TyWithLocation (value, value_locus),
     296                 :             :                      field.get_locus ());
     297                 :        1280 :   if (resolved_field_value_expr != nullptr)
     298                 :             :     {
     299                 :        1280 :       fields_assigned.insert (field.field_name.as_string ());
     300                 :        1280 :       adtFieldIndexToField[field_index] = &field;
     301                 :             :     }
     302                 :             : 
     303                 :             :   return true;
     304                 :             : }
     305                 :             : 
     306                 :             : bool
     307                 :          43 : TypeCheckStructExpr::visit (HIR::StructExprFieldIndexValue &field)
     308                 :             : {
     309                 :          43 :   std::string field_name (std::to_string (field.get_tuple_index ()));
     310                 :             : 
     311                 :          43 :   size_t field_index;
     312                 :          43 :   TyTy::StructFieldType *field_type;
     313                 :          43 :   bool ok = variant->lookup_field (field_name, &field_type, &field_index);
     314                 :          43 :   if (!ok)
     315                 :             :     {
     316                 :           1 :       rust_error_at (field.get_locus (), "unknown field");
     317                 :           1 :       return true;
     318                 :             :     }
     319                 :             : 
     320                 :          42 :   auto it = adtFieldIndexToField.find (field_index);
     321                 :          42 :   if (it != adtFieldIndexToField.end ())
     322                 :             :     {
     323                 :           0 :       rich_location repeat_location (line_table, field.get_locus ());
     324                 :           0 :       auto prev_field_locus = it->second->get_locus ();
     325                 :           0 :       repeat_location.add_range (prev_field_locus);
     326                 :             : 
     327                 :           0 :       rust_error_at (repeat_location, ErrorCode::E0062,
     328                 :             :                      "field %qs specified more than once",
     329                 :             :                      field_name.c_str ());
     330                 :           0 :       return false;
     331                 :           0 :     }
     332                 :             : 
     333                 :          42 :   TyTy::BaseType *value = TypeCheckExpr::Resolve (field.get_value ().get ());
     334                 :          42 :   location_t value_locus = field.get_value ()->get_locus ();
     335                 :             : 
     336                 :          42 :   HirId coercion_site_id = field.get_mappings ().get_hirid ();
     337                 :          42 :   resolved_field_value_expr
     338                 :          84 :     = coercion_site (coercion_site_id,
     339                 :             :                      TyTy::TyWithLocation (field_type->get_field_type (),
     340                 :          42 :                                            field_type->get_locus ()),
     341                 :          42 :                      TyTy::TyWithLocation (value, value_locus),
     342                 :             :                      field.get_locus ());
     343                 :          42 :   if (resolved_field_value_expr != nullptr)
     344                 :             :     {
     345                 :          42 :       fields_assigned.insert (field_name);
     346                 :          42 :       adtFieldIndexToField[field_index] = &field;
     347                 :             :     }
     348                 :             : 
     349                 :             :   return true;
     350                 :          43 : }
     351                 :             : 
     352                 :             : bool
     353                 :         211 : TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifier &field)
     354                 :             : {
     355                 :         211 :   size_t field_index;
     356                 :         211 :   TyTy::StructFieldType *field_type;
     357                 :         211 :   bool ok = variant->lookup_field (field.get_field_name ().as_string (),
     358                 :             :                                    &field_type, &field_index);
     359                 :         211 :   if (!ok)
     360                 :             :     {
     361                 :           0 :       rust_error_at (field.get_locus (), "unknown field");
     362                 :           0 :       return true;
     363                 :             :     }
     364                 :             : 
     365                 :         211 :   auto it = adtFieldIndexToField.find (field_index);
     366                 :         211 :   if (it != adtFieldIndexToField.end ())
     367                 :             :     {
     368                 :           0 :       rich_location repeat_location (line_table, field.get_locus ());
     369                 :           0 :       auto prev_field_locus = it->second->get_locus ();
     370                 :           0 :       repeat_location.add_range (prev_field_locus);
     371                 :             : 
     372                 :           0 :       rust_error_at (repeat_location, ErrorCode::E0062,
     373                 :             :                      "field %qs specified more than once",
     374                 :           0 :                      field.get_field_name ().as_string ().c_str ());
     375                 :           0 :       return false;
     376                 :           0 :     }
     377                 :             : 
     378                 :             :   // we can make the field look like a path expr to take advantage of existing
     379                 :             :   // code
     380                 :         211 :   Analysis::NodeMapping mappings_copy1 = field.get_mappings ();
     381                 :         211 :   Analysis::NodeMapping mappings_copy2 = field.get_mappings ();
     382                 :             : 
     383                 :         211 :   HIR::PathIdentSegment ident_seg (field.get_field_name ().as_string ());
     384                 :         211 :   HIR::PathExprSegment seg (mappings_copy1, ident_seg, field.get_locus (),
     385                 :         422 :                             HIR::GenericArgs::create_empty ());
     386                 :         211 :   HIR::PathInExpression expr (mappings_copy2, {seg}, field.get_locus (), false,
     387                 :         422 :                               {});
     388                 :         211 :   TyTy::BaseType *value = TypeCheckExpr::Resolve (&expr);
     389                 :         211 :   location_t value_locus = expr.get_locus ();
     390                 :             : 
     391                 :         211 :   HirId coercion_site_id = field.get_mappings ().get_hirid ();
     392                 :         211 :   resolved_field_value_expr
     393                 :         422 :     = coercion_site (coercion_site_id,
     394                 :             :                      TyTy::TyWithLocation (field_type->get_field_type (),
     395                 :         211 :                                            field_type->get_locus ()),
     396                 :         211 :                      TyTy::TyWithLocation (value, value_locus),
     397                 :             :                      field.get_locus ());
     398                 :         211 :   if (resolved_field_value_expr != nullptr)
     399                 :             : 
     400                 :             :     {
     401                 :         211 :       fields_assigned.insert (field.get_field_name ().as_string ());
     402                 :         211 :       adtFieldIndexToField[field_index] = &field;
     403                 :             :     }
     404                 :             : 
     405                 :         211 :   return true;
     406                 :         422 : }
     407                 :             : 
     408                 :             : Error
     409                 :           3 : TypeCheckStructExpr::make_missing_field_error (
     410                 :             :   location_t locus, const std::vector<std::string> &missing_field_names,
     411                 :             :   const std::string &struct_name)
     412                 :             : {
     413                 :             :   // Message plurality depends on size
     414                 :           3 :   if (missing_field_names.size () == 1)
     415                 :             :     {
     416                 :           1 :       return Error (locus, ErrorCode::E0063,
     417                 :             :                     "missing field %s in initializer of %qs",
     418                 :           1 :                     missing_field_names[0].c_str (), struct_name.c_str ());
     419                 :             :     }
     420                 :             :   // Make comma separated string for display
     421                 :           2 :   std::stringstream display_field_names;
     422                 :           2 :   bool first = true;
     423                 :           7 :   for (auto &name : missing_field_names)
     424                 :             :     {
     425                 :           5 :       if (!first)
     426                 :             :         {
     427                 :           3 :           display_field_names << ", ";
     428                 :             :         }
     429                 :           5 :       first = false;
     430                 :           5 :       display_field_names << name;
     431                 :             :     }
     432                 :           2 :   return Error (locus, ErrorCode::E0063,
     433                 :             :                 "missing fields %s in initializer of %qs",
     434                 :           2 :                 display_field_names.str ().c_str (), struct_name.c_str ());
     435                 :           2 : }
     436                 :             : 
     437                 :             : } // namespace Resolver
     438                 :             : } // namespace Rust
        

Generated by: LCOV version 2.1-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.