LCOV - code coverage report
Current view: top level - gcc/rust/typecheck - rust-coercion.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 92.5 % 345 319
Test Date: 2026-09-12 16:25:28 Functions: 94.1 % 17 16
Legend: Lines:     hit not hit

            Line data    Source code
       1              : // Copyright (C) 2020-2026 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-coercion.h"
      20              : #include "rust-type-util.h"
      21              : #include "rust-tyty.h"
      22              : 
      23              : namespace Rust {
      24              : namespace Resolver {
      25              : 
      26              : TypeCoercionRules::CoercionResult
      27        42954 : TypeCoercionRules::Coerce (TyTy::BaseType *receiver, TyTy::BaseType *expected,
      28              :                            location_t locus, bool allow_autoderef,
      29              :                            bool is_cast_site)
      30              : {
      31        42954 :   TypeCoercionRules resolver (expected, locus, true, allow_autoderef, false,
      32        42954 :                               is_cast_site);
      33        42954 :   bool ok = resolver.do_coercion (receiver);
      34        85854 :   return ok ? resolver.try_result : CoercionResult::get_error ();
      35        42954 : }
      36              : 
      37              : TypeCoercionRules::CoercionResult
      38        35133 : TypeCoercionRules::TryCoerce (TyTy::BaseType *receiver,
      39              :                               TyTy::BaseType *expected, location_t locus,
      40              :                               bool allow_autoderef, bool is_cast_site)
      41              : {
      42        35133 :   TypeCoercionRules resolver (expected, locus, false, allow_autoderef, true,
      43        35133 :                               is_cast_site);
      44        35133 :   bool ok = resolver.do_coercion (receiver);
      45        44756 :   return ok ? resolver.try_result : CoercionResult::get_error ();
      46        35133 : }
      47              : 
      48        78087 : TypeCoercionRules::TypeCoercionRules (TyTy::BaseType *expected,
      49              :                                       location_t locus, bool emit_errors,
      50              :                                       bool allow_autoderef, bool try_flag,
      51              :                                       bool is_cast_site)
      52       156174 :   : AutoderefCycle (!allow_autoderef), mappings (Analysis::Mappings::get ()),
      53        78087 :     context (TypeCheckContext::get ()), expected (expected), locus (locus),
      54        78087 :     try_result (CoercionResult::get_error ()), emit_errors (emit_errors),
      55        78087 :     try_flag (try_flag), is_cast_site (is_cast_site)
      56        78087 : {}
      57              : 
      58              : bool
      59        78087 : TypeCoercionRules::do_coercion (TyTy::BaseType *receiver)
      60              : {
      61              :   // FIXME this is not finished and might be super simplified
      62              :   // see:
      63              :   // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/coercion.rs
      64              : 
      65        78087 :   if (receiver->get_kind () == TyTy::TypeKind::NEVER)
      66              :     {
      67          461 :       try_result = coerce_never (receiver);
      68          461 :       return true;
      69              :     }
      70              : 
      71              :   // unsize
      72        77626 :   tl::expected<CoercionResult, CoerceUnsizedError> unsize_coercion
      73        77626 :     = coerce_unsized (receiver, expected);
      74        77626 :   if (unsize_coercion)
      75              :     {
      76          236 :       try_result = unsize_coercion.value ();
      77          236 :       return true;
      78              :     }
      79        77390 :   else if (unsize_coercion.error () == CoerceUnsizedError::Unsafe)
      80              :     {
      81              :       // location_t lhs = mappings.lookup_location (receiver->get_ref ());
      82              :       // location_t rhs = mappings.lookup_location (expected->get_ref ());
      83              :       // object_unsafe_error (locus, lhs, rhs);
      84              :       return false;
      85              :     }
      86              : 
      87              :   // pointers
      88        77217 :   switch (expected->get_kind ())
      89              :     {
      90         7917 :     case TyTy::TypeKind::POINTER:
      91         7917 :       {
      92         7917 :         auto *ptr = expected->as<TyTy::PointerType> ();
      93         7917 :         try_result = coerce_unsafe_ptr (receiver, ptr, ptr->mutability ());
      94         7917 :         return !try_result.is_error ();
      95              :       }
      96              : 
      97        23105 :     case TyTy::TypeKind::REF:
      98        23105 :       {
      99        23105 :         auto *ptr = expected->as<TyTy::ReferenceType> ();
     100        23105 :         try_result
     101        23105 :           = coerce_borrowed_pointer (receiver, ptr, ptr->mutability ());
     102        23105 :         return !try_result.is_error ();
     103              :       }
     104        46195 :       break;
     105              : 
     106        46195 :     default:
     107        46195 :       break;
     108              :     }
     109              : 
     110              :   // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/coercion.rs#L210
     111        46195 :   switch (receiver->get_kind ())
     112              :     {
     113        46195 :     default:
     114        46195 :       {
     115        46195 :         rust_debug (
     116              :           "do_coercion default unify and infer expected: %s receiver %s",
     117              :           receiver->debug_str ().c_str (), expected->debug_str ().c_str ());
     118        46195 :         TyTy::BaseType *result
     119        46195 :           = unify_site_and (receiver->get_ref (),
     120        46195 :                             TyTy::TyWithLocation (expected),
     121        46195 :                             TyTy::TyWithLocation (receiver),
     122              :                             locus /*unify_locus*/, false /*emit_errors*/,
     123              :                             !try_flag /*commit_if_ok*/, try_flag /*infer*/,
     124              :                             try_flag /*cleanup on error*/);
     125        46195 :         if (result->get_kind () != TyTy::TypeKind::ERROR)
     126              :           {
     127        36206 :             try_result = CoercionResult{{}, result};
     128        36206 :             return true;
     129              :           }
     130              :       }
     131         9989 :       break;
     132              :     }
     133              : 
     134         9989 :   return !try_result.is_error ();
     135        78087 : }
     136              : 
     137              : TypeCoercionRules::CoercionResult
     138          461 : TypeCoercionRules::coerce_never (TyTy::BaseType *receiver)
     139              : {
     140              :   // handle never
     141              :   // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/coercion.rs#L155
     142              : 
     143              :   // Subtle: If we are coercing from `!` to `?T`, where `?T` is an unbound
     144              :   // type variable, we want `?T` to fallback to `!` if not
     145              :   // otherwise constrained. An example where this arises:
     146              :   //
     147              :   //     let _: Option<?T> = Some({ return; });
     148              :   //
     149              :   // here, we would coerce from `!` to `?T`.
     150          461 :   if (expected->has_substitutions_defined () && !expected->is_concrete ())
     151              :     {
     152            1 :       location_t locus = mappings.lookup_location (receiver->get_ref ());
     153            1 :       TyTy::TyVar implicit_var = TyTy::TyVar::get_implicit_infer_var (locus);
     154            1 :       return CoercionResult{{}, implicit_var.get_tyty ()};
     155              :     }
     156              : 
     157          460 :   bool expected_is_infer_var = expected->get_kind () == TyTy::TypeKind::INFER;
     158          460 :   bool expected_is_general_infer_var
     159              :     = expected_is_infer_var
     160          460 :       && (static_cast<TyTy::InferType *> (expected)->get_infer_kind ()
     161          460 :           == TyTy::InferType::InferTypeKind::GENERAL);
     162              : 
     163              :   // FIXME this 'expected_is_general_infer_var' case needs to eventually
     164              :   // should go away see: compile/never_type_err1.rs
     165              :   //
     166              :   // I think we need inference obligations to say that yes we have a
     167              :   // general inference variable but we add the oligation to the expected
     168              :   // type that it could default to '!'
     169          460 :   if (expected_is_general_infer_var)
     170            1 :     return CoercionResult{{}, receiver};
     171              :   else
     172          459 :     return CoercionResult{{}, expected->clone ()};
     173              : }
     174              : 
     175              : TypeCoercionRules::CoercionResult
     176         7917 : TypeCoercionRules::coerce_unsafe_ptr (TyTy::BaseType *receiver,
     177              :                                       TyTy::PointerType *expected,
     178              :                                       Mutability to_mutbl)
     179              : {
     180         7917 :   rust_debug ("coerce_unsafe_ptr(receiver={%s}, expected={%s})",
     181              :               receiver->debug_str ().c_str (), expected->debug_str ().c_str ());
     182              : 
     183         7917 :   Mutability from_mutbl = Mutability::Imm;
     184         7917 :   TyTy::BaseType *element = nullptr;
     185         7917 :   switch (receiver->get_kind ())
     186              :     {
     187         4230 :     case TyTy::TypeKind::REF:
     188         4230 :       {
     189         4230 :         TyTy::ReferenceType *ref
     190              :           = static_cast<TyTy::ReferenceType *> (receiver);
     191         4230 :         from_mutbl = ref->mutability ();
     192         4230 :         element = ref->get_base ();
     193              :       }
     194         4230 :       break;
     195              : 
     196         3547 :     case TyTy::TypeKind::POINTER:
     197         3547 :       {
     198         3547 :         TyTy::PointerType *ref = static_cast<TyTy::PointerType *> (receiver);
     199         3547 :         from_mutbl = ref->mutability ();
     200         3547 :         element = ref->get_base ();
     201              :       }
     202         3547 :       break;
     203              : 
     204          140 :     default:
     205          140 :       {
     206          140 :         if (types_compatable (TyTy::TyWithLocation (receiver),
     207          140 :                               TyTy::TyWithLocation (expected), UNKNOWN_LOCATION,
     208              :                               false))
     209            0 :           return CoercionResult{{}, expected->clone ()};
     210              : 
     211          140 :         return CoercionResult::get_error ();
     212              :       }
     213              :     }
     214              : 
     215         7777 :   bool receiver_is_non_ptr = receiver->get_kind () != TyTy::TypeKind::POINTER;
     216         7777 :   if (autoderef_flag && receiver_is_non_ptr)
     217              :     {
     218              :       // it is unsafe to autoderef to raw pointers
     219           14 :       return CoercionResult::get_error ();
     220              :     }
     221              : 
     222         7763 :   if (!coerceable_mutability (from_mutbl, to_mutbl))
     223              :     {
     224            0 :       location_t lhs = mappings.lookup_location (receiver->get_ref ());
     225            0 :       location_t rhs = mappings.lookup_location (expected->get_ref ());
     226            0 :       mismatched_mutability_error (locus, lhs, rhs);
     227            0 :       return TypeCoercionRules::CoercionResult::get_error ();
     228              :     }
     229              : 
     230         7763 :   TyTy::PointerType *coerced_mutability
     231              :     = new TyTy::PointerType (receiver->get_ref (),
     232         7763 :                              TyTy::TyVar (element->get_ref ()), to_mutbl);
     233              : 
     234         7763 :   rust_debug ("coerce_unsafe_ptr unify-site");
     235              : 
     236              :   // this is a really annoying case rust allows casts of any ptr to another ptr
     237              :   // types
     238              :   //
     239              :   //  *?   vs *i32  - simple coercion valid
     240              :   //  *?   vs *T    - simple coercion valid
     241              :   //  *i32 vs *i32  - simple coercion valid
     242              :   //  *i32 vs *u8   - simple coercion not valid but allowed in cast site
     243              :   //  *T   vs *u8   - not valid but is allowed in cast site
     244              : 
     245         7763 :   TyTy::BaseType *result
     246        15526 :     = unify_site_and (receiver->get_ref (), TyTy::TyWithLocation (expected),
     247         7763 :                       TyTy::TyWithLocation (coerced_mutability),
     248              :                       locus /*unify_locus*/, !try_flag /*emit_errors*/,
     249              :                       !try_flag /*commit_if_ok*/,
     250         2308 :                       try_flag && !is_cast_site /*infer*/,
     251              :                       try_flag /*cleanup on error*/);
     252         7763 :   bool unsafe_ptr_coerceion_ok = result->get_kind () != TyTy::TypeKind::ERROR;
     253         7763 :   if (unsafe_ptr_coerceion_ok)
     254         7700 :     return CoercionResult{{}, result};
     255              : 
     256           63 :   return TypeCoercionRules::CoercionResult::get_error ();
     257              : }
     258              : 
     259              : /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.
     260              : /// To match `A` with `B`, autoderef will be performed,
     261              : /// calling `deref`/`deref_mut` where necessary.
     262              : TypeCoercionRules::CoercionResult
     263        23105 : TypeCoercionRules::coerce_borrowed_pointer (TyTy::BaseType *receiver,
     264              :                                             TyTy::ReferenceType *expected,
     265              :                                             Mutability to_mutbl)
     266              : {
     267        23105 :   rust_debug ("coerce_borrowed_pointer(a={%s}, b={%s})",
     268              :               receiver->debug_str ().c_str (), expected->debug_str ().c_str ());
     269              : 
     270        23105 :   Mutability from_mutbl = Mutability::Imm;
     271        23105 :   switch (receiver->get_kind ())
     272              :     {
     273        10787 :     case TyTy::TypeKind::REF:
     274        10787 :       {
     275        10787 :         from_mutbl = receiver->as<TyTy::ReferenceType> ()->mutability ();
     276              :       }
     277        10787 :       break;
     278        12318 :     default:
     279        12318 :       {
     280        12318 :         rust_debug ("coerce_borrowed_pointer -- unify");
     281        12318 :         TyTy::BaseType *result
     282        12318 :           = unify_site_and (receiver->get_ref (),
     283        12318 :                             TyTy::TyWithLocation (receiver),
     284        12318 :                             TyTy::TyWithLocation (expected), locus,
     285              :                             false /*emit_errors*/, !try_flag /*commit_if_ok*/,
     286              :                             try_flag /* infer */,
     287              :                             try_flag /*cleanup_on_failure*/);
     288        12318 :         bool default_coerceion_ok
     289        12318 :           = result->get_kind () != TyTy::TypeKind::ERROR;
     290        12318 :         if (default_coerceion_ok)
     291           21 :           return CoercionResult{{}, result};
     292              : 
     293        12297 :         return TypeCoercionRules::CoercionResult::get_error ();
     294              :       }
     295              :     }
     296              : 
     297        10787 :   if (!coerceable_mutability (from_mutbl, to_mutbl))
     298              :     {
     299            0 :       location_t lhs = mappings.lookup_location (receiver->get_ref ());
     300            0 :       location_t rhs = mappings.lookup_location (expected->get_ref ());
     301            0 :       mismatched_mutability_error (locus, lhs, rhs);
     302            0 :       return TypeCoercionRules::CoercionResult::get_error ();
     303              :     }
     304              : 
     305        10787 :   rust_debug ("coerce_borrowed_pointer -- autoderef cycle");
     306        10787 :   AutoderefCycle::cycle (receiver);
     307        18686 :   rust_debug ("coerce_borrowed_pointer -- result: [%s] with adjustments: [%zu]",
     308              :               try_result.is_error () ? "failed" : "matched",
     309              :               try_result.adjustments.size ());
     310              : 
     311        10787 :   return try_result;
     312              : }
     313              : 
     314              : // &[T; n] or &mut [T; n] -> &[T]
     315              : // or &mut [T; n] -> &mut [T]
     316              : // or &Concrete -> &Trait, etc.
     317              : // https://doc.rust-lang.org/stable/reference/type-coercions.html
     318              : tl::expected<TypeCoercionRules::CoercionResult,
     319              :              TypeCoercionRules::CoerceUnsizedError>
     320        78036 : TypeCoercionRules::coerce_unsized (TyTy::BaseType *source,
     321              :                                    TyTy::BaseType *target, bool is_inner)
     322              : {
     323        78036 :   rust_debug ("coerce_unsized(source={%s}, target={%s})",
     324              :               source->debug_str ().c_str (), target->debug_str ().c_str ());
     325        78036 :   size_t adjustments_size = adjustments.size ();
     326              : 
     327        78036 :   auto setup = unwrap_ptrs_and_refs (source, target);
     328        78036 :   if (!setup)
     329          172 :     return tl::unexpected<CoerceUnsizedError> (setup.error ());
     330              : 
     331              :   // FIXME
     332              :   // there is a bunch of code to ensure something is coerce able to a dyn
     333              :   // trait we need to support but we need to support a few more lang items for
     334              :   // that see:
     335              :   // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/coercion.rs#L582
     336              : 
     337        77864 :   auto a = setup->ty_a;
     338        77864 :   auto b = setup->ty_b;
     339              : 
     340        77864 :   tl::expected<TyTy::BaseType *, CoerceUnsizedError> inner_result
     341              :     = tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Regular);
     342              : 
     343        77864 :   bool expect_dyn = b->get_kind () == TyTy::TypeKind::DYNAMIC;
     344        77864 :   bool need_unsize = a->get_kind () != TyTy::TypeKind::DYNAMIC;
     345              : 
     346        77864 :   bool expect_slice = b->get_kind () == TyTy::TypeKind::SLICE;
     347        77864 :   bool is_array = a->get_kind () == TyTy::TypeKind::ARRAY;
     348              : 
     349        77864 :   bool expect_adt = b->get_kind () == TyTy::TypeKind::ADT;
     350        77864 :   bool is_adt = a->get_kind () == TyTy::TypeKind::ADT;
     351              : 
     352        77864 :   if (expect_dyn && need_unsize)
     353          194 :     inner_result
     354          196 :       = (!setup->unwrapped_pointer && !is_inner)
     355          388 :           ? tl::unexpected<CoerceUnsizedError> (inner_result.error ())
     356          194 :           : coerce_unsized_dyn (a, b);
     357              : 
     358        77670 :   else if (expect_slice && is_array)
     359          132 :     inner_result
     360          139 :       = (!setup->unwrapped_pointer && !is_inner)
     361          264 :           ? tl::unexpected<CoerceUnsizedError> (inner_result.error ())
     362          132 :           : coerce_unsized_array_to_slice (a, b);
     363              : 
     364        77538 :   else if (expect_adt && is_adt)
     365         3795 :     inner_result = coerce_unsized_adt (a, b, setup->needs_reborrow);
     366              : 
     367        77864 :   if (!inner_result)
     368              :     {
     369       155214 :       adjustments.erase (adjustments.begin () + adjustments_size,
     370        77607 :                          adjustments.end ());
     371        77607 :       return tl::unexpected<CoerceUnsizedError> (inner_result.error ());
     372              :     }
     373              : 
     374          257 :   TyTy::BaseType *result = inner_result.value ();
     375              : 
     376          257 :   if (setup->needs_reborrow)
     377          236 :     result = apply_reborrow_adjustment (source, target, result,
     378              :                                         setup->expected_mutability);
     379              : 
     380          257 :   return CoercionResult{adjustments, result};
     381              : }
     382              : 
     383              : tl::expected<TypeCoercionRules::CoercionSetup,
     384              :              TypeCoercionRules::CoerceUnsizedError>
     385        78036 : TypeCoercionRules::unwrap_ptrs_and_refs (TyTy::BaseType *source,
     386              :                                          TyTy::BaseType *target)
     387              : {
     388        78036 :   bool source_is_ref = source->get_kind () == TyTy::TypeKind::REF;
     389        78036 :   bool source_is_ptr = source->get_kind () == TyTy::TypeKind::POINTER;
     390        78036 :   bool target_is_ref = target->get_kind () == TyTy::TypeKind::REF;
     391        78036 :   bool target_is_ptr = target->get_kind () == TyTy::TypeKind::POINTER;
     392              : 
     393        78036 :   bool needs_reborrow = false;
     394        78036 :   bool unwrapped_pointer = false;
     395        78036 :   TyTy::BaseType *ty_a = source;
     396        78036 :   TyTy::BaseType *ty_b = target;
     397        78036 :   Mutability expected_mutability = Mutability::Imm;
     398        78036 :   if (source_is_ref && target_is_ref)
     399              :     {
     400        11185 :       TyTy::ReferenceType *source_ref
     401              :         = static_cast<TyTy::ReferenceType *> (source);
     402        11185 :       TyTy::ReferenceType *target_ref
     403              :         = static_cast<TyTy::ReferenceType *> (target);
     404              : 
     405        11185 :       Mutability from_mutbl = source_ref->mutability ();
     406        11185 :       Mutability to_mutbl = target_ref->mutability ();
     407        11185 :       if (!coerceable_mutability (from_mutbl, to_mutbl))
     408              :         {
     409          172 :           location_t lhs = mappings.lookup_location (source->get_ref ());
     410          172 :           location_t rhs = mappings.lookup_location (target->get_ref ());
     411          172 :           mismatched_mutability_error (locus, lhs, rhs);
     412          172 :           return tl::unexpected<CoerceUnsizedError> (
     413          172 :             CoerceUnsizedError::Unsafe);
     414              :         }
     415              : 
     416        11013 :       ty_a = source_ref->get_base ();
     417        11013 :       ty_b = target_ref->get_base ();
     418        11013 :       needs_reborrow = true;
     419        11013 :       unwrapped_pointer = true;
     420        11013 :       expected_mutability = to_mutbl;
     421              : 
     422        11013 :       adjustments.emplace_back (Adjustment::AdjustmentType::INDIRECTION,
     423              :                                 source_ref, ty_a);
     424              :     }
     425        66851 :   else if (source_is_ref && target_is_ptr)
     426              :     {
     427         4233 :       TyTy::ReferenceType *source_ref
     428              :         = static_cast<TyTy::ReferenceType *> (source);
     429         4233 :       TyTy::PointerType *target_ref = static_cast<TyTy::PointerType *> (target);
     430              : 
     431         4233 :       Mutability from_mutbl = source_ref->mutability ();
     432         4233 :       Mutability to_mutbl = target_ref->mutability ();
     433         4233 :       if (!coerceable_mutability (from_mutbl, to_mutbl))
     434              :         {
     435            0 :           location_t lhs = mappings.lookup_location (source->get_ref ());
     436            0 :           location_t rhs = mappings.lookup_location (target->get_ref ());
     437            0 :           mismatched_mutability_error (locus, lhs, rhs);
     438            0 :           return tl::unexpected<CoerceUnsizedError> (
     439            0 :             CoerceUnsizedError::Unsafe);
     440              :         }
     441              : 
     442         4233 :       ty_a = source_ref->get_base ();
     443         4233 :       ty_b = target_ref->get_base ();
     444         4233 :       needs_reborrow = true;
     445         4233 :       unwrapped_pointer = true;
     446         4233 :       expected_mutability = to_mutbl;
     447              : 
     448         4233 :       adjustments.emplace_back (Adjustment::AdjustmentType::INDIRECTION,
     449              :                                 source_ref, ty_a);
     450              :     }
     451        62618 :   else if (source_is_ptr && target_is_ptr)
     452              :     {
     453         3555 :       TyTy::PointerType *source_ref = static_cast<TyTy::PointerType *> (source);
     454         3555 :       TyTy::PointerType *target_ref = static_cast<TyTy::PointerType *> (target);
     455              : 
     456         3555 :       Mutability from_mutbl = source_ref->mutability ();
     457         3555 :       Mutability to_mutbl = target_ref->mutability ();
     458         3555 :       if (!coerceable_mutability (from_mutbl, to_mutbl))
     459              :         {
     460            0 :           location_t lhs = mappings.lookup_location (source->get_ref ());
     461            0 :           location_t rhs = mappings.lookup_location (target->get_ref ());
     462            0 :           mismatched_mutability_error (locus, lhs, rhs);
     463            0 :           return tl::unexpected<CoerceUnsizedError> (
     464            0 :             CoerceUnsizedError::Unsafe);
     465              :         }
     466              : 
     467         3555 :       ty_a = source_ref->get_base ();
     468         3555 :       ty_b = target_ref->get_base ();
     469         3555 :       needs_reborrow = true;
     470         3555 :       unwrapped_pointer = true;
     471         3555 :       expected_mutability = to_mutbl;
     472              : 
     473         3555 :       adjustments.emplace_back (Adjustment::AdjustmentType::INDIRECTION,
     474              :                                 source_ref, ty_a);
     475              :     }
     476              : 
     477        77864 :   return CoercionSetup{ty_a, ty_b, needs_reborrow, expected_mutability,
     478        77864 :                        unwrapped_pointer};
     479              : }
     480              : 
     481              : tl::expected<TyTy::BaseType *, TypeCoercionRules::CoerceUnsizedError>
     482          132 : TypeCoercionRules::coerce_unsized_array_to_slice (TyTy::BaseType *a,
     483              :                                                   TyTy::BaseType *b)
     484              : {
     485          132 :   auto array_type = static_cast<const TyTy::ArrayType *> (a);
     486          132 :   auto slice_type = static_cast<const TyTy::SliceType *> (b);
     487              : 
     488          132 :   TyTy::BaseType *array_element = array_type->get_element_type ();
     489          132 :   TyTy::BaseType *slice_element = slice_type->get_element_type ();
     490              : 
     491          132 :   if (!array_element->is_equal (*slice_element))
     492           89 :     return tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Regular);
     493              : 
     494           43 :   TyTy::BaseType *result = b->clone ();
     495              : 
     496           43 :   adjustments.emplace_back (Adjustment::UNSIZE, a, result);
     497              : 
     498           43 :   return result;
     499              : }
     500              : tl::expected<TyTy::BaseType *, TypeCoercionRules::CoerceUnsizedError>
     501          194 : TypeCoercionRules::coerce_unsized_dyn (TyTy::BaseType *a, TyTy::BaseType *b)
     502              : {
     503          194 :   bool bounds_compatible = b->bounds_compatible (*a, locus, false);
     504          194 :   if (!bounds_compatible)
     505            1 :     return tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Unsafe);
     506              : 
     507              :   // return the unsize coercion
     508          193 :   TyTy::BaseType *result = b->clone ();
     509              :   // result->set_ref (a->get_ref ());
     510              : 
     511              :   // append a dyn coercion adjustment
     512          193 :   adjustments.emplace_back (Adjustment::UNSIZE, a, result);
     513              : 
     514          193 :   return result;
     515              : }
     516              : tl::expected<TyTy::BaseType *, TypeCoercionRules::CoerceUnsizedError>
     517         3795 : TypeCoercionRules::coerce_unsized_adt (TyTy::BaseType *a, TyTy::BaseType *b,
     518              :                                        bool needs_reborrow)
     519              : {
     520         3795 :   auto source_adt = static_cast<const TyTy::ADTType *> (a);
     521         3795 :   auto target_adt = static_cast<const TyTy::ADTType *> (b);
     522              : 
     523         3795 :   if ((!source_adt->is_struct_struct () && !source_adt->is_tuple_struct ())
     524         2415 :       || (!target_adt->is_struct_struct () && !target_adt->is_tuple_struct ())
     525         6207 :       || (source_adt->get_id () != target_adt->get_id ())
     526         6014 :       || (source_adt->get_variants ().front ()->num_fields ()
     527         2219 :           != target_adt->get_variants ().front ()->num_fields ()))
     528         1576 :     return tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Regular);
     529              : 
     530         2219 :   auto source_variant = source_adt->get_variants ().front ();
     531         2219 :   auto target_variant = target_adt->get_variants ().front ();
     532              : 
     533         2219 :   TyTy::BaseType *differing_source_field = nullptr;
     534         2219 :   TyTy::BaseType *differing_target_field = nullptr;
     535         2219 :   size_t diff_count = 0;
     536         2219 :   bool is_last_field = false;
     537              : 
     538         6553 :   for (size_t i = 0; i < source_variant->num_fields (); i++)
     539              :     {
     540         4334 :       auto s_field_raw
     541         4334 :         = source_variant->get_field_at_index (i)->get_field_type ();
     542         4334 :       auto t_field_raw
     543         4334 :         = target_variant->get_field_at_index (i)->get_field_type ();
     544         4334 :       auto s_field = s_field_raw->contains_infer ()
     545         4334 :                        ? s_field_raw
     546         4147 :                        : s_field_raw->monomorphized_clone ();
     547         4334 :       auto t_field = t_field_raw->contains_infer ()
     548         4334 :                        ? t_field_raw
     549         4256 :                        : t_field_raw->monomorphized_clone ();
     550              : 
     551              :       // https://doc.rust-lang.org/reference/dynamically-sized-types.html
     552         4334 :       if (!s_field->is_equal (*t_field))
     553              :         {
     554          484 :           if (s_field->is<TyTy::ADTType> () && t_field->is<TyTy::ADTType> ())
     555           25 :             if (auto phantom_data
     556           25 :                 = mappings.lookup_lang_item (LangItem::Kind::PHANTOM_DATA))
     557            9 :               if (s_field->as<TyTy::ADTType> ()->get_id () == phantom_data
     558            9 :                   && t_field->as<TyTy::ADTType> ()->get_id () == phantom_data)
     559            3 :                 continue;
     560              : 
     561          428 :           differing_source_field = s_field;
     562          428 :           differing_target_field = t_field;
     563          428 :           diff_count++;
     564          428 :           is_last_field = (i == source_variant->num_fields () - 1);
     565              :         }
     566              :     }
     567              : 
     568         2219 :   if (diff_count != 1)
     569         1807 :     return tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Regular);
     570              : 
     571          412 :   if (needs_reborrow && !is_last_field)
     572            2 :     return tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Regular);
     573              : 
     574          410 :   auto adjustments_size = adjustments.size ();
     575          410 :   auto inner_coercion
     576          410 :     = coerce_unsized (differing_source_field, differing_target_field, true);
     577          410 :   if (!inner_coercion)
     578          389 :     return tl::unexpected<CoerceUnsizedError> (inner_coercion.error ());
     579           42 :   adjustments.erase (adjustments.begin () + adjustments_size,
     580           21 :                      adjustments.end ());
     581              : 
     582           21 :   TyTy::BaseType *result = b->clone ();
     583           21 :   adjustments.emplace_back (Adjustment::UNSIZE, a, result);
     584              : 
     585           21 :   return result;
     586         3795 : }
     587              : TyTy::BaseType *
     588          236 : TypeCoercionRules::apply_reborrow_adjustment (TyTy::BaseType *source,
     589              :                                               TyTy::BaseType *target,
     590              :                                               TyTy::BaseType *result,
     591              :                                               Mutability expected_mutability)
     592              : {
     593          236 :   TyTy::BaseType *reborrow = nullptr;
     594              : 
     595          236 :   if (target->get_kind () == TyTy::TypeKind::POINTER)
     596              :     {
     597           22 :       reborrow = new TyTy::PointerType (source->get_ref (),
     598           11 :                                         TyTy::TyVar (result->get_ref ()),
     599           22 :                                         expected_mutability);
     600              :     }
     601              :   else
     602              :     {
     603          450 :       reborrow = new TyTy::ReferenceType (source->get_ref (),
     604          225 :                                           TyTy::TyVar (result->get_ref ()),
     605          450 :                                           expected_mutability);
     606              :     }
     607              : 
     608          472 :   Adjustment::AdjustmentType borrow_type
     609          236 :     = expected_mutability == Mutability::Imm ? Adjustment::IMM_REF
     610              :                                              : Adjustment::MUT_REF;
     611              : 
     612          236 :   adjustments.emplace_back (borrow_type, result, reborrow);
     613          236 :   return reborrow;
     614              : }
     615              : 
     616              : bool
     617        16991 : TypeCoercionRules::select (TyTy::BaseType &autoderefed)
     618              : {
     619        16991 :   rust_debug ("TypeCoercionRules::select autoderefed={%s} can_eq expected={%s}",
     620              :               autoderefed.debug_str ().c_str (),
     621              :               expected->debug_str ().c_str ());
     622              : 
     623        16991 :   TyTy::BaseType *result
     624        16991 :     = unify_site_and (autoderefed.get_ref (), TyTy::TyWithLocation (expected),
     625        16991 :                       TyTy::TyWithLocation (&autoderefed),
     626              :                       UNDEF_LOCATION /* locus */, false /*emit_errors*/,
     627              :                       !try_flag /*commit_if_ok*/, try_flag /*infer*/,
     628              :                       try_flag /*cleanup*/);
     629        16991 :   bool ok = result->get_kind () != TyTy::TypeKind::ERROR;
     630        16991 :   if (!ok)
     631              :     return false;
     632              : 
     633         7899 :   try_result = CoercionResult{adjustments, result};
     634         7899 :   return true;
     635              : }
     636              : 
     637              : /// Coercing a mutable reference to an immutable works, while
     638              : /// coercing `&T` to `&mut T` should be forbidden.
     639              : bool
     640        37523 : TypeCoercionRules::coerceable_mutability (Mutability from_mutbl,
     641              :                                           Mutability to_mutbl)
     642              : {
     643        37523 :   return to_mutbl == Mutability::Imm || (from_mutbl == to_mutbl);
     644              : }
     645              : 
     646              : void
     647          172 : TypeCoercionRules::mismatched_mutability_error (location_t expr_locus,
     648              :                                                 location_t lhs, location_t rhs)
     649              : {
     650          172 :   if (!emit_errors)
     651              :     return;
     652              : 
     653            1 :   rich_location r (line_table, expr_locus);
     654            1 :   r.add_range (lhs);
     655            1 :   r.add_range (rhs);
     656            1 :   rust_error_at (r, "mismatched mutability");
     657            1 : }
     658              : 
     659              : void
     660            0 : TypeCoercionRules::object_unsafe_error (location_t expr_locus, location_t lhs,
     661              :                                         location_t rhs)
     662              : {
     663            0 :   if (!emit_errors)
     664              :     return;
     665              : 
     666            0 :   rich_location r (line_table, expr_locus);
     667            0 :   r.add_range (lhs);
     668            0 :   r.add_range (rhs);
     669            0 :   rust_error_at (r, "unsafe unsize coercion");
     670            0 : }
     671              : 
     672              : } // namespace Resolver
     673              : } // namespace Rust
        

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