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

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