LCOV - code coverage report
Current view: top level - gcc/rust/typecheck - rust-hir-type-check-expr.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 87.4 % 1386 1212
Test Date: 2026-08-22 16:33:35 Functions: 98.1 % 52 51
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 "optional.h"
      20              : #include "rust-common.h"
      21              : #include "rust-diagnostics.h"
      22              : #include "rust-hir-expr.h"
      23              : #include "rust-hir-map.h"
      24              : #include "rust-rib.h"
      25              : #include "rust-system.h"
      26              : #include "rust-tyty-call.h"
      27              : #include "rust-hir-type-check-struct-field.h"
      28              : #include "rust-hir-path-probe.h"
      29              : #include "rust-substitution-mapper.h"
      30              : #include "rust-hir-trait-resolve.h"
      31              : #include "rust-hir-dot-operator.h"
      32              : #include "rust-hir-type-check-pattern.h"
      33              : #include "rust-hir-type-check-expr.h"
      34              : #include "rust-hir-type-check-stmt.h"
      35              : #include "rust-hir-type-check-item.h"
      36              : #include "rust-type-util.h"
      37              : #include "rust-finalized-name-resolution-context.h"
      38              : #include "rust-compile-base.h"
      39              : #include "rust-tyty-util.h"
      40              : #include "rust-tyty.h"
      41              : 
      42              : namespace Rust {
      43              : namespace Resolver {
      44              : 
      45       151747 : TypeCheckExpr::TypeCheckExpr () : TypeCheckBase (), infered (nullptr) {}
      46              : 
      47              : // Perform type checking on expr. Also runs type unification algorithm.
      48              : // Returns the unified type of expr
      49              : TyTy::BaseType *
      50       151739 : TypeCheckExpr::Resolve (HIR::Expr &expr)
      51              : {
      52       151739 :   TypeCheckExpr resolver;
      53       151739 :   expr.accept_vis (resolver);
      54              : 
      55       151739 :   if (resolver.infered == nullptr)
      56           86 :     return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
      57              : 
      58       151653 :   if (resolver.infered->get_kind () != TyTy::TypeKind::CONST)
      59              :     {
      60       151516 :       auto ref = expr.get_mappings ().get_hirid ();
      61       151516 :       resolver.infered->set_ref (ref);
      62              :     }
      63       151653 :   resolver.context->insert_type (expr.get_mappings (), resolver.infered);
      64              : 
      65       151653 :   if (auto fn = resolver.infered->try_as<const TyTy::FnType> ())
      66              :     {
      67        10843 :       if (fn->is_syn_constant ())
      68           28 :         resolver.infered = fn->get_return_type ();
      69              :     }
      70              : 
      71       151653 :   return resolver.infered;
      72       151739 : }
      73              : 
      74              : TyTy::BaseType *
      75            8 : TypeCheckExpr::ResolveOpOverload (LangItem::Kind lang_item_type,
      76              :                                   HIR::OperatorExprMeta expr,
      77              :                                   TyTy::BaseType *lhs, TyTy::BaseType *rhs,
      78              :                                   HIR::PathIdentSegment specified_segment)
      79              : {
      80            8 :   TypeCheckExpr resolver;
      81              : 
      82           16 :   resolver.resolve_operator_overload (lang_item_type, expr, lhs, rhs,
      83              :                                       specified_segment);
      84            8 :   return resolver.infered;
      85            8 : }
      86              : 
      87              : void
      88          900 : TypeCheckExpr::visit (HIR::TupleIndexExpr &expr)
      89              : {
      90          900 :   auto resolved = TypeCheckExpr::Resolve (expr.get_tuple_expr ());
      91          900 :   if (resolved->get_kind () == TyTy::TypeKind::ERROR)
      92              :     {
      93            0 :       rust_error_at (expr.get_tuple_expr ().get_locus (),
      94              :                      "failed to resolve TupleIndexExpr receiver");
      95            0 :       return;
      96              :     }
      97              : 
      98              :   // FIXME does this require autoderef here?
      99          900 :   if (resolved->get_kind () == TyTy::TypeKind::REF)
     100              :     {
     101          317 :       TyTy::ReferenceType *r = static_cast<TyTy::ReferenceType *> (resolved);
     102          317 :       resolved = r->get_base ();
     103              :     }
     104              : 
     105          900 :   bool is_valid_type = resolved->get_kind () == TyTy::TypeKind::ADT
     106          900 :                        || resolved->get_kind () == TyTy::TypeKind::TUPLE;
     107            2 :   if (!is_valid_type)
     108              :     {
     109            2 :       rust_error_at (expr.get_tuple_expr ().get_locus (),
     110              :                      "Expected Tuple or ADT got: %s",
     111            2 :                      resolved->as_string ().c_str ());
     112            2 :       return;
     113              :     }
     114              : 
     115          898 :   if (resolved->get_kind () == TyTy::TypeKind::TUPLE)
     116              :     {
     117          151 :       TyTy::TupleType *tuple = static_cast<TyTy::TupleType *> (resolved);
     118          151 :       TupleIndex index = expr.get_tuple_index ();
     119          151 :       if ((size_t) index >= tuple->num_fields ())
     120              :         {
     121            1 :           rust_error_at (expr.get_locus (), ErrorCode::E0609,
     122              :                          "no field %qi on type %qs", index,
     123            1 :                          resolved->get_name ().c_str ());
     124            1 :           return;
     125              :         }
     126              : 
     127          150 :       auto field_tyty = tuple->get_field ((size_t) index);
     128          150 :       if (field_tyty == nullptr)
     129              :         {
     130            0 :           rust_error_at (expr.get_locus (),
     131              :                          "failed to lookup field type at index %i", index);
     132            0 :           return;
     133              :         }
     134              : 
     135          150 :       infered = field_tyty;
     136          150 :       return;
     137              :     }
     138              : 
     139          747 :   TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (resolved);
     140          747 :   if (!adt->is_tuple_struct ())
     141              :     {
     142            2 :       rust_error_at (expr.get_locus (),
     143              :                      "expected tuple or tuple struct, found %qs",
     144            2 :                      adt->get_name ().c_str ());
     145            2 :       return;
     146              :     }
     147          745 :   rust_assert (adt->number_of_variants () == 1);
     148              : 
     149          745 :   TyTy::VariantDef *variant = adt->get_variants ().at (0);
     150          745 :   TupleIndex index = expr.get_tuple_index ();
     151          745 :   if ((size_t) index >= variant->num_fields ())
     152              :     {
     153            0 :       rust_error_at (expr.get_locus (), "unknown field at index %i", index);
     154            0 :       return;
     155              :     }
     156              : 
     157          745 :   auto field_tyty = variant->get_field_at_index ((size_t) index);
     158          745 :   if (field_tyty == nullptr)
     159              :     {
     160            0 :       rust_error_at (expr.get_locus (),
     161              :                      "failed to lookup field type at index %i", index);
     162            0 :       return;
     163              :     }
     164              : 
     165          745 :   infered = field_tyty->get_field_type ();
     166              : }
     167              : 
     168              : void
     169          583 : TypeCheckExpr::visit (HIR::TupleExpr &expr)
     170              : {
     171          583 :   if (expr.is_unit ())
     172              :     {
     173          152 :       infered = TyTy::TupleType::get_unit_type ();
     174          152 :       return;
     175              :     }
     176              : 
     177          431 :   std::vector<TyTy::TyVar> fields;
     178         1433 :   for (auto &elem : expr.get_tuple_elems ())
     179              :     {
     180         1002 :       auto field_ty = TypeCheckExpr::Resolve (*elem);
     181         1002 :       fields.emplace_back (field_ty->get_ref ());
     182              :     }
     183          862 :   infered = new TyTy::TupleType (expr.get_mappings ().get_hirid (),
     184          862 :                                  expr.get_locus (), fields);
     185          431 : }
     186              : 
     187              : void
     188            3 : TypeCheckExpr::visit (HIR::BoxExpr &expr)
     189              : {
     190            3 :   auto owned_box_defid
     191            3 :     = mappings.get_lang_item (LangItem::Kind::OWNED_BOX, expr.get_locus ());
     192              : 
     193            3 :   HIR::Item *item = mappings.lookup_defid (owned_box_defid).value ();
     194            3 :   TyTy::BaseType *item_type = nullptr;
     195              : 
     196            3 :   bool ok
     197            3 :     = context->lookup_type (item->get_mappings ().get_hirid (), &item_type);
     198            3 :   rust_assert (ok);
     199            3 :   if (item_type->get_kind () != TyTy::TypeKind::ADT)
     200              :     {
     201            0 :       rust_error_at (item->get_locus (), ErrorCode::E0718,
     202              :                      "%qs language item must be applied to a struct",
     203              :                      "owned_box");
     204            2 :       return;
     205              :     }
     206            3 :   TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (item_type);
     207            3 :   if (!adt->is_tuple_struct () && !adt->is_struct_struct ())
     208              :     {
     209            1 :       rust_error_at (item->get_locus (), ErrorCode::E0718,
     210              :                      "%qs language item must be applied to a struct",
     211              :                      "owned_box");
     212            1 :       return;
     213              :     }
     214              : 
     215              :   // this is at least one generic item
     216            2 :   if (adt->get_num_substitutions () < 1)
     217              :     {
     218            1 :       rust_error_at (expr.get_locus (),
     219              :                      "%qs lang item must be applied to a struct with at least "
     220              :                      "1 generic argument",
     221              :                      "owned_box");
     222            1 :       return;
     223              :     }
     224              : 
     225            1 :   TyTy::BaseType *inner_ty = TypeCheckExpr::Resolve (expr.get_expr ());
     226            1 :   if (inner_ty->get_kind () == TyTy::TypeKind::ERROR)
     227              :     {
     228            0 :       infered = inner_ty;
     229            0 :       return;
     230              :     }
     231              : 
     232            1 :   auto lookup = SubstMapper::InferSubst (adt, expr.get_locus ());
     233            1 :   rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
     234            1 :   TyTy::ADTType *adt_box = static_cast<TyTy::ADTType *> (lookup);
     235              : 
     236            1 :   TyTy::BaseType *infer = adt_box->get_substs ().at (0).get_param_ty ();
     237              : 
     238            2 :   unify_site (expr.get_mappings ().get_hirid (),
     239            1 :               TyTy::TyWithLocation (infer, expr.get_locus ()),
     240            1 :               TyTy::TyWithLocation (inner_ty, expr.get_locus ()),
     241              :               expr.get_locus ());
     242              : 
     243            1 :   infered = adt_box;
     244              : }
     245              : 
     246              : void
     247          553 : TypeCheckExpr::visit (HIR::ReturnExpr &expr)
     248              : {
     249          553 :   if (!context->have_function_context ())
     250              :     {
     251            1 :       rust_error_at (expr.get_locus (), ErrorCode::E0572,
     252              :                      "return statement outside of function body");
     253            1 :       infered = new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
     254            1 :       return;
     255              :     }
     256              : 
     257          552 :   auto fn_return_tyty = context->peek_return_type ();
     258          552 :   location_t expr_locus = expr.has_return_expr ()
     259          552 :                             ? expr.get_expr ().get_locus ()
     260           34 :                             : expr.get_locus ();
     261              : 
     262              :   // Push expected type so the resolver of the return expression
     263              :   // inference before checking its arguments which is needed
     264              :   // for things like:
     265              :   //
     266              :   //    return Try::from_error(...)
     267              :   //
     268              :   // Where Self has to bind from the fn return type before the param
     269              :   // projection can be normalized.
     270          552 :   TyTy::BaseType *expr_ty;
     271          552 :   if (expr.has_return_expr ())
     272              :     {
     273          518 :       context->push_expected_type (fn_return_tyty);
     274          518 :       expr_ty = TypeCheckExpr::Resolve (expr.get_expr ());
     275          518 :       context->pop_expected_type ();
     276              :     }
     277              :   else
     278           34 :     expr_ty = TyTy::TupleType::get_unit_type ();
     279              : 
     280         1104 :   coercion_site (expr.get_mappings ().get_hirid (),
     281          552 :                  TyTy::TyWithLocation (fn_return_tyty),
     282          552 :                  TyTy::TyWithLocation (expr_ty, expr_locus), expr.get_locus ());
     283              : 
     284          552 :   infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ());
     285              : }
     286              : 
     287              : void
     288        12677 : TypeCheckExpr::visit (HIR::CallExpr &expr)
     289              : {
     290        12677 :   TyTy::BaseType *function_tyty = TypeCheckExpr::Resolve (expr.get_fnexpr ());
     291              : 
     292        12677 :   rust_debug_loc (expr.get_locus (), "resolved_call_expr to: {%s}",
     293        12677 :                   function_tyty->get_name ().c_str ());
     294              : 
     295        12677 :   TyTy::VariantDef &variant = TyTy::VariantDef::get_error_node ();
     296        12677 :   if (function_tyty->get_kind () == TyTy::TypeKind::ADT)
     297              :     {
     298         1817 :       TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (function_tyty);
     299         1817 :       if (adt->is_enum ())
     300              :         {
     301              :           // lookup variant id
     302          895 :           HirId variant_id;
     303          895 :           bool ok = context->lookup_variant_definition (
     304          895 :             expr.get_fnexpr ().get_mappings ().get_hirid (), &variant_id);
     305              : 
     306          895 :           if (!ok)
     307              :             {
     308            1 :               rust_error_at (expr.get_locus (), ErrorCode::E0423,
     309              :                              "expected function, tuple struct or tuple "
     310              :                              "variant, found enum");
     311            1 :               return;
     312              :             }
     313              : 
     314          894 :           TyTy::VariantDef *lookup_variant = nullptr;
     315          894 :           ok = adt->lookup_variant_by_id (variant_id, &lookup_variant);
     316          894 :           rust_assert (ok);
     317              : 
     318          894 :           variant = std::move (*lookup_variant->clone ());
     319              :         }
     320              :       else
     321              :         {
     322          922 :           rust_assert (adt->number_of_variants () == 1);
     323          922 :           variant = std::move (*adt->get_variants ().at (0)->clone ());
     324              :         }
     325         1816 :       infered
     326         1816 :         = TyTy::TypeCheckCallExpr::go (function_tyty, expr, variant, context);
     327         1816 :       return;
     328              :     }
     329              : 
     330        10860 :   bool resolved_fn_trait_call
     331        10860 :     = resolve_fn_trait_call (expr, function_tyty, &infered);
     332        10860 :   if (resolved_fn_trait_call)
     333              :     return;
     334              : 
     335        10794 :   bool valid_tyty
     336        10834 :     = function_tyty->is<TyTy::FnType> () || function_tyty->is<TyTy::FnPtr> ();
     337           11 :   if (!valid_tyty)
     338              :     {
     339           11 :       bool emit_error = !function_tyty->is<TyTy::ErrorType> ();
     340           11 :       if (emit_error)
     341              :         {
     342            2 :           rich_location r (line_table, expr.get_locus ());
     343            2 :           rust_error_at (r, ErrorCode::E0618, "expected function, found %<%s%>",
     344            2 :                          function_tyty->get_name ().c_str ());
     345            2 :         }
     346              :       return;
     347              :     }
     348              : 
     349        10783 :   infered = TyTy::TypeCheckCallExpr::go (function_tyty, expr, variant, context);
     350              : 
     351              :   // Pre-GATS: associated types were PlaceholderType; post-GATS they are
     352              :   // ProjectionType, this hHandle both so the isize special-case still fires
     353        10783 :   auto discriminant_type_lookup
     354        10783 :     = mappings.lookup_lang_item (LangItem::Kind::DISCRIMINANT_TYPE);
     355        10783 :   bool is_discriminant_type = false;
     356        10783 :   if (discriminant_type_lookup)
     357              :     {
     358          824 :       if (auto *p = infered->try_as<TyTy::PlaceholderType> ())
     359            0 :         is_discriminant_type
     360            0 :           = p->get_def_id () == discriminant_type_lookup.value ();
     361        11607 :       else if (auto *p = infered->try_as<TyTy::ProjectionType> ())
     362            0 :         is_discriminant_type
     363            0 :           = p->get_item_defid () == discriminant_type_lookup.value ();
     364              :     }
     365            0 :   if (is_discriminant_type)
     366              :     {
     367              :       // This is a special case: discriminant_value returns the repr of the
     368              :       // enum. We don't currently support repr on enum yet, so the default
     369              :       // is always isize.
     370            0 :       bool ok = context->lookup_builtin ("isize", &infered);
     371            0 :       rust_assert (ok);
     372              : 
     373            0 :       rust_assert (function_tyty->is<TyTy::FnType> ());
     374            0 :       auto &fn = *static_cast<TyTy::FnType *> (function_tyty);
     375            0 :       rust_assert (fn.has_substitutions ());
     376            0 :       rust_assert (fn.get_num_type_params () == 1);
     377            0 :       auto &mapping = fn.get_substs ().at (0);
     378            0 :       auto param_ty = mapping.get_param_ty ();
     379              : 
     380            0 :       if (!param_ty->can_resolve ())
     381              :         {
     382            0 :           rust_internal_error_at (expr.get_locus (),
     383              :                                   "something wrong computing return type");
     384              :           return;
     385              :         }
     386              : 
     387            0 :       auto resolved = param_ty->resolve ();
     388            0 :       if (resolved->is<TyTy::ADTType> ())
     389              :         {
     390            0 :           const auto &adt = *static_cast<TyTy::ADTType *> (resolved);
     391            0 :           infered = adt.get_repr_options ().repr;
     392            0 :           rust_assert (infered != nullptr);
     393              :         }
     394              :     }
     395              : }
     396              : 
     397              : void
     398         2500 : TypeCheckExpr::visit (HIR::AssignmentExpr &expr)
     399              : {
     400         2500 :   infered = TyTy::TupleType::get_unit_type ();
     401              : 
     402         2500 :   auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
     403         2500 :   auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
     404              : 
     405         5000 :   coercion_site (expr.get_mappings ().get_hirid (),
     406         2500 :                  TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()),
     407         2500 :                  TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()),
     408              :                  expr.get_locus ());
     409         2500 : }
     410              : 
     411              : void
     412          697 : TypeCheckExpr::visit (HIR::CompoundAssignmentExpr &expr)
     413              : {
     414          697 :   infered = TyTy::TupleType::get_unit_type ();
     415              : 
     416          697 :   auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
     417          697 :   auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
     418              : 
     419              :   // we dont care about the result of the unify from a compound assignment
     420              :   // since this is a unit-type expr
     421         1394 :   coercion_site (expr.get_mappings ().get_hirid (),
     422          697 :                  TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()),
     423          697 :                  TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()),
     424              :                  expr.get_locus ());
     425              : 
     426          697 :   auto lang_item_type
     427          697 :     = LangItem::CompoundAssignmentOperatorToLangItem (expr.get_expr_type ());
     428          697 :   bool operator_overloaded
     429          697 :     = resolve_operator_overload (lang_item_type, expr, lhs, rhs);
     430          697 :   if (operator_overloaded)
     431              :     return;
     432              : 
     433          683 :   bool valid_lhs = validate_arithmetic_type (lhs, expr.get_expr_type ());
     434          683 :   bool valid_rhs = validate_arithmetic_type (rhs, expr.get_expr_type ());
     435          683 :   bool valid = valid_lhs && valid_rhs;
     436          683 :   if (!valid)
     437              :     {
     438            0 :       rust_error_at (expr.get_locus (),
     439              :                      "cannot apply operator %qs to types %s and %s",
     440            0 :                      expr.get_operator_str ().c_str (),
     441            0 :                      lhs->as_string ().c_str (), rhs->as_string ().c_str ());
     442            0 :       return;
     443              :     }
     444              : }
     445              : 
     446              : void
     447        20826 : TypeCheckExpr::visit (HIR::LiteralExpr &expr)
     448              : {
     449        20826 :   infered = resolve_literal (expr.get_mappings (), expr.get_literal (),
     450              :                              expr.get_locus ());
     451        20826 : }
     452              : 
     453              : void
     454         3415 : TypeCheckExpr::visit (HIR::ArithmeticOrLogicalExpr &expr)
     455              : {
     456         3415 :   auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
     457         3415 :   auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
     458              : 
     459         3415 :   auto lang_item_type = LangItem::OperatorToLangItem (expr.get_expr_type ());
     460         3415 :   bool operator_overloaded
     461         3415 :     = resolve_operator_overload (lang_item_type, expr, lhs, rhs);
     462         3415 :   if (operator_overloaded)
     463              :     return;
     464              : 
     465         3246 :   bool valid_lhs = validate_arithmetic_type (lhs, expr.get_expr_type ());
     466         3246 :   bool valid_rhs = validate_arithmetic_type (rhs, expr.get_expr_type ());
     467         3246 :   bool valid = valid_lhs && valid_rhs;
     468         3246 :   if (!valid)
     469              :     {
     470            6 :       rust_error_at (expr.get_locus (),
     471              :                      "cannot apply operator %qs to types %s and %s",
     472            6 :                      expr.get_operator_str ().c_str (),
     473            6 :                      lhs->as_string ().c_str (), rhs->as_string ().c_str ());
     474            3 :       return;
     475              :     }
     476              : 
     477         3243 :   switch (expr.get_expr_type ())
     478              :     {
     479           69 :     case ArithmeticOrLogicalOperator::LEFT_SHIFT:
     480           69 :     case ArithmeticOrLogicalOperator::RIGHT_SHIFT:
     481           69 :       {
     482           69 :         TyTy::TyWithLocation from (rhs, expr.get_rhs ().get_locus ());
     483           69 :         TyTy::TyWithLocation to (lhs, expr.get_lhs ().get_locus ());
     484           69 :         infered = cast_site (expr.get_mappings ().get_hirid (), from, to,
     485              :                              expr.get_locus ());
     486              :       }
     487           69 :       break;
     488              : 
     489         3174 :     default:
     490         3174 :       {
     491         6348 :         infered = unify_site (
     492         3174 :           expr.get_mappings ().get_hirid (),
     493         3174 :           TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()),
     494         3174 :           TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()),
     495              :           expr.get_locus ());
     496              :       }
     497         3174 :       break;
     498              :     }
     499              : }
     500              : 
     501              : void
     502         3566 : TypeCheckExpr::visit (HIR::ComparisonExpr &expr)
     503              : {
     504         3566 :   auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
     505         3566 :   auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
     506              : 
     507         3566 :   auto borrowed_rhs
     508         3566 :     = new TyTy::ReferenceType (mappings.get_next_hir_id (),
     509         3566 :                                TyTy::TyVar (rhs->get_ref ()), Mutability::Imm);
     510         3566 :   context->insert_implicit_type (borrowed_rhs->get_ref (), borrowed_rhs);
     511              : 
     512         3566 :   auto seg_name = LangItem::ComparisonToSegment (expr.get_expr_type ());
     513         7132 :   auto segment = HIR::PathIdentSegment (seg_name);
     514         3566 :   auto lang_item_type = LangItem::ComparisonToLangItem (expr.get_expr_type ());
     515              : 
     516         3566 :   bool operator_overloaded
     517         3566 :     = resolve_operator_overload (lang_item_type, expr, lhs, borrowed_rhs,
     518              :                                  segment);
     519         3566 :   if (operator_overloaded)
     520          955 :     return;
     521              : 
     522         5222 :   unify_site (expr.get_mappings ().get_hirid (),
     523         2611 :               TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()),
     524         2611 :               TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()),
     525              :               expr.get_locus ());
     526              : 
     527         2611 :   bool ok = context->lookup_builtin ("bool", &infered);
     528         2611 :   rust_assert (ok);
     529         3566 : }
     530              : 
     531              : void
     532          405 : TypeCheckExpr::visit (HIR::LazyBooleanExpr &expr)
     533              : {
     534          405 :   auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
     535          405 :   auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
     536              : 
     537              :   // we expect the lhs and rhs must be bools at this point
     538          405 :   TyTy::BaseType *boolean_node = nullptr;
     539          405 :   bool ok = context->lookup_builtin ("bool", &boolean_node);
     540          405 :   rust_assert (ok);
     541              : 
     542              :   // verify the lhs and rhs before unifying together
     543          810 :   lhs = unify_site (expr.get_mappings ().get_hirid (),
     544              :                     TyTy::TyWithLocation (boolean_node,
     545          405 :                                           expr.get_lhs ().get_locus ()),
     546          405 :                     TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()),
     547              :                     expr.get_locus ());
     548              : 
     549          810 :   rhs = unify_site (expr.get_mappings ().get_hirid (),
     550              :                     TyTy::TyWithLocation (boolean_node,
     551          405 :                                           expr.get_rhs ().get_locus ()),
     552          405 :                     TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()),
     553              :                     expr.get_locus ());
     554              : 
     555          405 :   infered
     556          810 :     = unify_site (expr.get_mappings ().get_hirid (),
     557          405 :                   TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()),
     558          405 :                   TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()),
     559              :                   expr.get_locus ());
     560          405 : }
     561              : 
     562              : void
     563          687 : TypeCheckExpr::visit (HIR::NegationExpr &expr)
     564              : {
     565          687 :   auto negated_expr_ty = TypeCheckExpr::Resolve (expr.get_expr ());
     566              : 
     567              :   // check for operator overload
     568          687 :   auto lang_item_type
     569          687 :     = LangItem::NegationOperatorToLangItem (expr.get_expr_type ());
     570          687 :   bool operator_overloaded
     571          687 :     = resolve_operator_overload (lang_item_type, expr, negated_expr_ty,
     572              :                                  nullptr);
     573          687 :   if (operator_overloaded)
     574              :     return;
     575              : 
     576              :   // https://doc.rust-lang.org/reference/expressions/operator-expr.html#negation-operators
     577          673 :   switch (expr.get_expr_type ())
     578              :     {
     579          408 :     case NegationOperator::NEGATE:
     580          408 :       {
     581          408 :         bool valid
     582          408 :           = (negated_expr_ty->get_kind () == TyTy::TypeKind::INT)
     583          268 :             || (negated_expr_ty->get_kind () == TyTy::TypeKind::UINT)
     584          268 :             || (negated_expr_ty->get_kind () == TyTy::TypeKind::FLOAT)
     585          266 :             || (negated_expr_ty->get_kind () == TyTy::TypeKind::ISIZE)
     586          263 :             || (negated_expr_ty->get_kind () == TyTy::TypeKind::USIZE)
     587          263 :             || (negated_expr_ty->get_kind () == TyTy::TypeKind::INFER
     588          262 :                 && (((TyTy::InferType *) negated_expr_ty)->get_infer_kind ()
     589              :                     == TyTy::InferType::INTEGRAL))
     590          409 :             || (negated_expr_ty->get_kind () == TyTy::TypeKind::INFER
     591            0 :                 && (((TyTy::InferType *) negated_expr_ty)->get_infer_kind ()
     592          672 :                     == TyTy::InferType::FLOAT));
     593            1 :         if (!valid)
     594              :           {
     595            1 :             rust_error_at (expr.get_locus (), "cannot apply unary - to %s",
     596            1 :                            negated_expr_ty->as_string ().c_str ());
     597            1 :             return;
     598              :           }
     599              :       }
     600              :       break;
     601              : 
     602          265 :     case NegationOperator::NOT:
     603          265 :       {
     604          265 :         bool valid
     605          265 :           = (negated_expr_ty->get_kind () == TyTy::TypeKind::BOOL)
     606           59 :             || (negated_expr_ty->get_kind () == TyTy::TypeKind::INT)
     607           52 :             || (negated_expr_ty->get_kind () == TyTy::TypeKind::UINT)
     608          275 :             || (negated_expr_ty->get_kind () == TyTy::TypeKind::INFER
     609            9 :                 && (((TyTy::InferType *) negated_expr_ty)->get_infer_kind ()
     610          672 :                     == TyTy::InferType::INTEGRAL));
     611            1 :         if (!valid)
     612              :           {
     613            1 :             rust_error_at (expr.get_locus (), "cannot apply unary %<!%> to %s",
     614            1 :                            negated_expr_ty->as_string ().c_str ());
     615            1 :             return;
     616              :           }
     617              :       }
     618              :       break;
     619              :     }
     620              : 
     621          671 :   infered = negated_expr_ty->clone ();
     622          671 :   infered->append_reference (negated_expr_ty->get_ref ());
     623              : }
     624              : 
     625              : void
     626         1252 : TypeCheckExpr::visit (HIR::IfExpr &expr)
     627              : {
     628         1252 :   TyTy::BaseType *bool_ty = nullptr;
     629         1252 :   bool ok = context->lookup_builtin ("bool", &bool_ty);
     630         1252 :   rust_assert (ok);
     631              : 
     632         1252 :   TyTy::BaseType *cond_type = TypeCheckExpr::Resolve (expr.get_if_condition ());
     633              : 
     634         2504 :   unify_site (expr.get_mappings ().get_hirid (), TyTy::TyWithLocation (bool_ty),
     635              :               TyTy::TyWithLocation (cond_type,
     636         1252 :                                     expr.get_if_condition ().get_locus ()),
     637              :               expr.get_locus ());
     638              : 
     639         1252 :   TyTy::BaseType *block_type = TypeCheckExpr::Resolve (expr.get_if_block ());
     640              : 
     641         1252 :   TyTy::BaseType *unit_ty = nullptr;
     642         1252 :   ok = context->lookup_builtin ("()", &unit_ty);
     643         1252 :   rust_assert (ok);
     644              : 
     645         1252 :   infered
     646         2504 :     = coercion_site (expr.get_mappings ().get_hirid (),
     647         1252 :                      TyTy::TyWithLocation (unit_ty),
     648              :                      TyTy::TyWithLocation (block_type,
     649         1252 :                                            expr.get_if_block ().get_locus ()),
     650              :                      expr.get_locus ());
     651         1252 : }
     652              : 
     653              : void
     654         1262 : TypeCheckExpr::visit (HIR::IfExprConseqElse &expr)
     655              : {
     656         1262 :   TyTy::BaseType *bool_ty = nullptr;
     657         1262 :   bool ok = context->lookup_builtin ("bool", &bool_ty);
     658         1262 :   rust_assert (ok);
     659              : 
     660         1262 :   TyTy::BaseType *cond_type = TypeCheckExpr::Resolve (expr.get_if_condition ());
     661              : 
     662         2524 :   unify_site (expr.get_mappings ().get_hirid (), TyTy::TyWithLocation (bool_ty),
     663              :               TyTy::TyWithLocation (cond_type,
     664         1262 :                                     expr.get_if_condition ().get_locus ()),
     665              :               expr.get_locus ());
     666              : 
     667         1262 :   auto if_blk_resolved = TypeCheckExpr::Resolve (expr.get_if_block ());
     668         1262 :   auto else_blk_resolved = TypeCheckExpr::Resolve (expr.get_else_block ());
     669              : 
     670         1262 :   if (if_blk_resolved->get_kind () == TyTy::NEVER)
     671           40 :     infered = else_blk_resolved;
     672         1222 :   else if (else_blk_resolved->get_kind () == TyTy::NEVER)
     673            7 :     infered = if_blk_resolved;
     674              :   else
     675              :     {
     676         1215 :       infered
     677         2430 :         = unify_site (expr.get_mappings ().get_hirid (),
     678              :                       TyTy::TyWithLocation (if_blk_resolved,
     679         1215 :                                             expr.get_if_block ().get_locus ()),
     680              :                       TyTy::TyWithLocation (
     681         1215 :                         else_blk_resolved, expr.get_else_block ().get_locus ()),
     682              :                       expr.get_locus ());
     683              :     }
     684         1262 : }
     685              : 
     686              : void
     687         3701 : TypeCheckExpr::visit (HIR::UnsafeBlockExpr &expr)
     688              : {
     689         3701 :   infered = TypeCheckExpr::Resolve (expr.get_block_expr ());
     690         3701 : }
     691              : 
     692              : void
     693        23467 : TypeCheckExpr::visit (HIR::BlockExpr &expr)
     694              : {
     695        23467 :   bool has_label = expr.has_label ();
     696        23467 :   if (expr.has_label ())
     697            3 :     context->push_new_loop_context (expr.get_mappings ().get_hirid (),
     698              :                                     expr.get_locus ());
     699              : 
     700              :   // Forward the caller's expected type to the block's tail expression only.
     701        23467 :   TyTy::BaseType *outer_expected = context->peek_expected_type ();
     702        23467 :   context->push_expected_type (nullptr);
     703              : 
     704        47982 :   for (auto &s : expr.get_statements ())
     705              :     {
     706        24515 :       if (!s->is_item ())
     707        24087 :         continue;
     708              : 
     709          428 :       TypeCheckStmt::Resolve (*s);
     710              :     }
     711              : 
     712        47982 :   for (auto &s : expr.get_statements ())
     713              :     {
     714        24515 :       if (s->is_item ())
     715          428 :         continue;
     716              : 
     717        24087 :       auto resolved = TypeCheckStmt::Resolve (*s);
     718        24087 :       if (resolved == nullptr)
     719              :         {
     720            0 :           rust_error_at (s->get_locus (), "failure to resolve type");
     721            0 :           context->pop_expected_type ();
     722            0 :           if (has_label)
     723            0 :             context->pop_loop_context ();
     724        23467 :           return;
     725              :         }
     726              : 
     727        24087 :       if (s->is_unit_check_needed () && !resolved->is_unit ())
     728              :         {
     729            6 :           auto unit = TyTy::TupleType::get_unit_type ();
     730           12 :           unify_site (s->get_mappings ().get_hirid (),
     731            6 :                       TyTy::TyWithLocation (unit),
     732            6 :                       TyTy::TyWithLocation (resolved), s->get_locus ());
     733              :         }
     734              :     }
     735              : 
     736        23467 :   context->pop_expected_type ();
     737              : 
     738        23467 :   TyTy::BaseType *tail_expr_type = nullptr;
     739        23467 :   if (expr.has_expr ())
     740              :     {
     741        16526 :       context->push_expected_type (outer_expected);
     742        16526 :       tail_expr_type = TypeCheckExpr::Resolve (expr.get_final_expr ());
     743        16526 :       context->pop_expected_type ();
     744              :     }
     745              : 
     746        23467 :   TyTy::BaseType *label_context_type = nullptr;
     747        23467 :   bool label_context_type_infered = false;
     748        23467 :   if (has_label)
     749              :     {
     750            3 :       label_context_type = context->pop_loop_context ();
     751              : 
     752            3 :       label_context_type_infered
     753            3 :         = (label_context_type->get_kind () != TyTy::TypeKind::INFER)
     754            3 :           || ((label_context_type->get_kind () == TyTy::TypeKind::INFER)
     755            3 :               && (((TyTy::InferType *) label_context_type)->get_infer_kind ()
     756              :                   != TyTy::InferType::GENERAL));
     757              :     }
     758              : 
     759        23467 :   if (tail_expr_type != nullptr)
     760              :     {
     761        16526 :       if (label_context_type_infered)
     762              :         {
     763            2 :           if (tail_expr_type->get_kind () == TyTy::TypeKind::NEVER)
     764            0 :             infered = label_context_type;
     765              :           else
     766            4 :             infered = unify_site (
     767            2 :               expr.get_mappings ().get_hirid (),
     768            2 :               TyTy::TyWithLocation (label_context_type),
     769              :               TyTy::TyWithLocation (tail_expr_type,
     770            2 :                                     expr.get_final_expr ().get_locus ()),
     771              :               expr.get_locus ());
     772              :         }
     773              :       else
     774        16524 :         infered = tail_expr_type;
     775              :     }
     776         6941 :   else if (label_context_type_infered)
     777            1 :     infered = label_context_type;
     778         6940 :   else if (expr.is_tail_reachable ())
     779         6467 :     infered = TyTy::TupleType::get_unit_type ();
     780              :   else
     781              :     {
     782              :       // FIXME this seems wrong
     783          473 :       infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ());
     784              :     }
     785              : }
     786              : 
     787              : void
     788          697 : TypeCheckExpr::visit (HIR::AnonConst &expr)
     789              : {
     790          697 :   if (!expr.is_deferred ())
     791              :     {
     792          685 :       infered = TypeCheckExpr::Resolve (expr.get_inner_expr ());
     793          685 :       return;
     794              :     }
     795              : 
     796           12 :   TyTy::TyVar var
     797           12 :     = TyTy::TyVar::get_implicit_const_infer_var (expr.get_locus ());
     798           12 :   infered = var.get_tyty ();
     799              : }
     800              : 
     801              : void
     802           15 : TypeCheckExpr::visit (HIR::ConstBlock &expr)
     803              : {
     804           15 :   infered = TypeCheckExpr::Resolve (expr.get_const_expr ());
     805           15 : }
     806              : 
     807              : void
     808           66 : TypeCheckExpr::visit (HIR::RangeFromToExpr &expr)
     809              : {
     810           66 :   auto lang_item_type = LangItem::Kind::RANGE;
     811              : 
     812           66 :   auto lang_item_defined = mappings.lookup_lang_item (lang_item_type);
     813              :   // we need to have it maybe
     814           66 :   if (!lang_item_defined)
     815              :     {
     816            0 :       rust_internal_error_at (expr.get_locus (),
     817              :                               "unable to find relevant lang item: %s",
     818            0 :                               LangItem::ToString (lang_item_type).c_str ());
     819              :       return;
     820              :     }
     821           66 :   DefId respective_lang_item_id = lang_item_defined.value ();
     822              : 
     823              :   // look it up and it _must_ be a struct definition
     824           66 :   HIR::Item *item = mappings.lookup_defid (respective_lang_item_id).value ();
     825              : 
     826           66 :   TyTy::BaseType *item_type = nullptr;
     827           66 :   bool ok
     828           66 :     = context->lookup_type (item->get_mappings ().get_hirid (), &item_type);
     829           66 :   rust_assert (ok);
     830           66 :   rust_assert (item_type->get_kind () == TyTy::TypeKind::ADT);
     831           66 :   TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (item_type);
     832              : 
     833              :   // this is a single generic item lets assert that
     834           66 :   rust_assert (adt->get_num_substitutions () == 1);
     835              : 
     836              :   // resolve the range expressions and these types must unify then we use that
     837              :   // type to substitute into the ADT
     838           66 :   TyTy::BaseType *from_ty = TypeCheckExpr::Resolve (expr.get_from_expr ());
     839           66 :   TyTy::BaseType *to_ty = TypeCheckExpr::Resolve (expr.get_to_expr ());
     840              : 
     841          132 :   TyTy::BaseType *unified = unify_site (
     842           66 :     expr.get_mappings ().get_hirid (),
     843           66 :     TyTy::TyWithLocation (from_ty, expr.get_from_expr ().get_locus ()),
     844           66 :     TyTy::TyWithLocation (to_ty, expr.get_to_expr ().get_locus ()),
     845           66 :     expr.get_locus ());
     846              : 
     847              :   // substitute it in
     848           66 :   std::vector<TyTy::SubstitutionArg> subst_mappings;
     849           66 :   const TyTy::SubstitutionParamMapping *param_ref = &adt->get_substs ().at (0);
     850           66 :   subst_mappings.emplace_back (param_ref, unified);
     851              : 
     852           66 :   TyTy::SubstitutionArgumentMappings subst (
     853           66 :     subst_mappings, {}, adt->get_substitution_arguments ().get_regions (),
     854           66 :     expr.get_locus ());
     855           66 :   infered = SubstMapperInternal::Resolve (adt, subst);
     856           66 : }
     857              : 
     858              : void
     859            7 : TypeCheckExpr::visit (HIR::RangeFromExpr &expr)
     860              : {
     861            7 :   auto lang_item_type = LangItem::Kind::RANGE_FROM;
     862              : 
     863            7 :   auto lang_item_defined = mappings.lookup_lang_item (lang_item_type);
     864              :   // we need to have it maybe
     865            7 :   if (!lang_item_defined)
     866              :     {
     867            0 :       rust_internal_error_at (expr.get_locus (),
     868              :                               "unable to find relevant lang item: %s",
     869            0 :                               LangItem::ToString (lang_item_type).c_str ());
     870              :       return;
     871              :     }
     872            7 :   DefId &respective_lang_item_id = lang_item_defined.value ();
     873              : 
     874              :   // look it up and it _must_ be a struct definition
     875            7 :   HIR::Item *item = mappings.lookup_defid (respective_lang_item_id).value ();
     876              : 
     877            7 :   TyTy::BaseType *item_type = nullptr;
     878            7 :   bool ok
     879            7 :     = context->lookup_type (item->get_mappings ().get_hirid (), &item_type);
     880            7 :   rust_assert (ok);
     881            7 :   rust_assert (item_type->get_kind () == TyTy::TypeKind::ADT);
     882            7 :   TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (item_type);
     883              : 
     884              :   // this is a single generic item lets assert that
     885            7 :   rust_assert (adt->get_num_substitutions () == 1);
     886              : 
     887              :   // resolve the range expressions and these types must unify then we use that
     888              :   // type to substitute into the ADT
     889            7 :   TyTy::BaseType *from_ty = TypeCheckExpr::Resolve (expr.get_from_expr ());
     890              : 
     891              :   // substitute it in
     892            7 :   std::vector<TyTy::SubstitutionArg> subst_mappings;
     893            7 :   const TyTy::SubstitutionParamMapping *param_ref = &adt->get_substs ().at (0);
     894            7 :   subst_mappings.emplace_back (param_ref, from_ty);
     895              : 
     896            7 :   TyTy::SubstitutionArgumentMappings subst (
     897            7 :     subst_mappings, {}, adt->get_substitution_arguments ().get_regions (),
     898            7 :     expr.get_locus ());
     899            7 :   infered = SubstMapperInternal::Resolve (adt, subst);
     900            7 : }
     901              : 
     902              : void
     903            7 : TypeCheckExpr::visit (HIR::RangeToExpr &expr)
     904              : {
     905            7 :   auto lang_item_type = LangItem::Kind::RANGE_TO;
     906              : 
     907            7 :   auto lang_item_defined = mappings.lookup_lang_item (lang_item_type);
     908              :   // we need to have it maybe
     909            7 :   if (!lang_item_defined)
     910              :     {
     911            0 :       rust_internal_error_at (expr.get_locus (),
     912              :                               "unable to find relevant lang item: %s",
     913            0 :                               LangItem::ToString (lang_item_type).c_str ());
     914              :       return;
     915              :     }
     916              : 
     917            7 :   DefId &respective_lang_item_id = lang_item_defined.value ();
     918              :   // look it up and it _must_ be a struct definition
     919            7 :   HIR::Item *item = mappings.lookup_defid (respective_lang_item_id).value ();
     920              : 
     921            7 :   TyTy::BaseType *item_type = nullptr;
     922            7 :   bool ok
     923            7 :     = context->lookup_type (item->get_mappings ().get_hirid (), &item_type);
     924            7 :   rust_assert (ok);
     925            7 :   rust_assert (item_type->get_kind () == TyTy::TypeKind::ADT);
     926            7 :   TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (item_type);
     927              : 
     928              :   // this is a single generic item lets assert that
     929            7 :   rust_assert (adt->get_num_substitutions () == 1);
     930              : 
     931              :   // resolve the range expressions and these types must unify then we use that
     932              :   // type to substitute into the ADT
     933            7 :   TyTy::BaseType *from_ty = TypeCheckExpr::Resolve (expr.get_to_expr ());
     934              : 
     935              :   // substitute it in
     936            7 :   std::vector<TyTy::SubstitutionArg> subst_mappings;
     937            7 :   const TyTy::SubstitutionParamMapping *param_ref = &adt->get_substs ().at (0);
     938            7 :   subst_mappings.emplace_back (param_ref, from_ty);
     939              : 
     940            7 :   TyTy::SubstitutionArgumentMappings subst (
     941            7 :     subst_mappings, {}, adt->get_substitution_arguments ().get_regions (),
     942            7 :     expr.get_locus ());
     943            7 :   infered = SubstMapperInternal::Resolve (adt, subst);
     944            7 : }
     945              : 
     946              : void
     947           27 : typecheck_inline_asm_operand (HIR::InlineAsm &expr)
     948              : {
     949           27 :   const auto &operands = expr.get_operands ();
     950           27 :   using RegisterType = AST::InlineAsmOperand::RegisterType;
     951           56 :   for (auto &operand : operands)
     952              :     {
     953           29 :       switch (operand.get_register_type ())
     954              :         {
     955           10 :         case RegisterType::In:
     956           10 :           {
     957           10 :             auto in = operand.get_in ();
     958           10 :             TypeCheckExpr::Resolve (*in.expr);
     959           10 :             break;
     960           10 :           }
     961           17 :         case RegisterType::Out:
     962           17 :           {
     963           17 :             auto out = operand.get_out ();
     964           17 :             TypeCheckExpr::Resolve (*out.expr);
     965           17 :             break;
     966           17 :           }
     967            0 :         case RegisterType::InOut:
     968            0 :           {
     969            0 :             auto in_out = operand.get_in_out ();
     970            0 :             TypeCheckExpr::Resolve (*in_out.expr);
     971            0 :             break;
     972            0 :           }
     973            2 :         case RegisterType::SplitInOut:
     974            2 :           {
     975            2 :             auto split_in_out = operand.get_split_in_out ();
     976            2 :             TypeCheckExpr::Resolve (*split_in_out.in_expr);
     977            2 :             TypeCheckExpr::Resolve (*split_in_out.out_expr);
     978            2 :             break;
     979            2 :           }
     980            0 :         case RegisterType::Const:
     981            0 :           {
     982            0 :             auto anon_const = operand.get_const ().anon_const;
     983            0 :             TypeCheckExpr::Resolve (anon_const.get_inner_expr ());
     984            0 :             break;
     985            0 :           }
     986            0 :         case RegisterType::Sym:
     987            0 :           {
     988            0 :             auto sym = operand.get_sym ();
     989            0 :             TypeCheckExpr::Resolve (*sym.expr);
     990            0 :             break;
     991            0 :           }
     992            0 :         case RegisterType::Label:
     993            0 :           {
     994            0 :             auto label = operand.get_label ();
     995            0 :             TypeCheckExpr::Resolve (*label.expr);
     996            0 :             break;
     997            0 :           }
     998              :         }
     999              :     }
    1000           27 : }
    1001              : void
    1002           27 : TypeCheckExpr::visit (HIR::InlineAsm &expr)
    1003              : {
    1004           27 :   typecheck_inline_asm_operand (expr);
    1005              : 
    1006              :   // NOTE: Hoise out if we have noreturn as an option
    1007              :   // to return a never type
    1008              :   // TODO : new keyword for memory seems sooooo shaky
    1009           27 :   if (expr.options.count (AST::InlineAsm::Option::NORETURN) == 1)
    1010            1 :     infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ());
    1011              :   else
    1012           26 :     infered = TyTy::TupleType::get_unit_type ();
    1013           27 : }
    1014              : 
    1015              : void
    1016            2 : TypeCheckExpr::visit (HIR::LlvmInlineAsm &expr)
    1017              : {
    1018            4 :   for (auto &i : expr.inputs)
    1019            2 :     TypeCheckExpr::Resolve (*i.expr);
    1020              : 
    1021            2 :   for (auto &o : expr.outputs)
    1022            0 :     TypeCheckExpr::Resolve (*o.expr);
    1023              : 
    1024              :   // Black box hint is unit type
    1025            2 :   infered = TyTy::TupleType::get_unit_type ();
    1026            2 : }
    1027              : 
    1028              : void
    1029           15 : TypeCheckExpr::visit (HIR::OffsetOf &expr)
    1030              : {
    1031           15 :   TypeCheckType::Resolve (expr.get_type ());
    1032              : 
    1033              :   // FIXME: Does offset_of always return a usize?
    1034           15 :   TyTy::BaseType *size_ty;
    1035           15 :   bool ok = context->lookup_builtin ("usize", &size_ty);
    1036           15 :   rust_assert (ok);
    1037              : 
    1038           15 :   infered = size_ty;
    1039           15 : }
    1040              : 
    1041              : void
    1042            0 : TypeCheckExpr::visit (HIR::RangeFullExpr &expr)
    1043              : {
    1044            0 :   auto lang_item_type = LangItem::Kind::RANGE_FULL;
    1045              : 
    1046            0 :   auto lang_item_defined = mappings.lookup_lang_item (lang_item_type);
    1047              :   // we need to have it maybe
    1048            0 :   if (!lang_item_defined)
    1049              :     {
    1050            0 :       rust_internal_error_at (expr.get_locus (),
    1051              :                               "unable to find relevant lang item: %s",
    1052            0 :                               LangItem::ToString (lang_item_type).c_str ());
    1053              :       return;
    1054              :     }
    1055            0 :   DefId &respective_lang_item_id = lang_item_defined.value ();
    1056              : 
    1057              :   // look it up and it _must_ be a struct definition
    1058            0 :   HIR::Item *item = mappings.lookup_defid (respective_lang_item_id).value ();
    1059              : 
    1060            0 :   TyTy::BaseType *item_type = nullptr;
    1061            0 :   bool ok
    1062            0 :     = context->lookup_type (item->get_mappings ().get_hirid (), &item_type);
    1063            0 :   rust_assert (ok);
    1064            0 :   rust_assert (item_type->is_unit ());
    1065              : 
    1066            0 :   infered = item_type;
    1067              : }
    1068              : 
    1069              : void
    1070          291 : TypeCheckExpr::visit (HIR::ArrayIndexExpr &expr)
    1071              : {
    1072          291 :   auto array_expr_ty = TypeCheckExpr::Resolve (expr.get_array_expr ());
    1073          291 :   if (array_expr_ty->get_kind () == TyTy::TypeKind::ERROR)
    1074          289 :     return;
    1075              : 
    1076          290 :   auto index_expr_ty = TypeCheckExpr::Resolve (expr.get_index_expr ());
    1077          290 :   if (index_expr_ty->get_kind () == TyTy::TypeKind::ERROR)
    1078              :     return;
    1079              : 
    1080              :   // first attempt to use direct array index logic
    1081          290 :   auto direct_array_expr_ty = array_expr_ty;
    1082          290 :   if (direct_array_expr_ty->get_kind () == TyTy::TypeKind::REF)
    1083              :     {
    1084              :       // lets try and deref it since rust allows this
    1085           29 :       auto ref = static_cast<TyTy::ReferenceType *> (direct_array_expr_ty);
    1086           29 :       auto base = ref->get_base ();
    1087           29 :       if (base->get_kind () == TyTy::TypeKind::ARRAY)
    1088          290 :         direct_array_expr_ty = base;
    1089              :     }
    1090              : 
    1091          290 :   TyTy::BaseType *size_ty;
    1092          290 :   bool ok = context->lookup_builtin ("usize", &size_ty);
    1093          290 :   rust_assert (ok);
    1094              : 
    1095          290 :   bool maybe_simple_array_access
    1096          290 :     = types_compatable (TyTy::TyWithLocation (index_expr_ty),
    1097          290 :                         TyTy::TyWithLocation (size_ty), expr.get_locus (),
    1098              :                         false);
    1099          290 :   if (maybe_simple_array_access
    1100          290 :       && direct_array_expr_ty->get_kind () == TyTy::TypeKind::ARRAY)
    1101              :     {
    1102          450 :       unify_site (expr.get_index_expr ().get_mappings ().get_hirid (),
    1103          225 :                   TyTy::TyWithLocation (size_ty),
    1104              :                   TyTy::TyWithLocation (index_expr_ty,
    1105          225 :                                         expr.get_index_expr ().get_locus ()),
    1106              :                   expr.get_locus ());
    1107              : 
    1108          225 :       TyTy::ArrayType *array_type
    1109              :         = static_cast<TyTy::ArrayType *> (direct_array_expr_ty);
    1110          225 :       infered = array_type->get_element_type ()->clone ();
    1111          225 :       return;
    1112              :     }
    1113              : 
    1114              :   // is this a case of core::ops::index?
    1115           65 :   auto lang_item_type = LangItem::Kind::INDEX;
    1116           65 :   bool operator_overloaded
    1117           65 :     = resolve_operator_overload (lang_item_type, expr, array_expr_ty,
    1118              :                                  index_expr_ty);
    1119           65 :   if (operator_overloaded)
    1120              :     {
    1121              :       // index and index mut always return a reference to the element
    1122           63 :       TyTy::BaseType *resolved = infered;
    1123           63 :       rust_assert (resolved->get_kind () == TyTy::TypeKind::REF);
    1124           63 :       TyTy::ReferenceType *ref = static_cast<TyTy::ReferenceType *> (resolved);
    1125              : 
    1126           63 :       infered = ref->get_base ()->clone ();
    1127           63 :       return;
    1128              :     }
    1129              : 
    1130              :   // error[E0277]: the type `[{integer}]` cannot be indexed by `u32`
    1131            2 :   rich_location r (line_table, expr.get_locus ());
    1132            2 :   r.add_range (expr.get_array_expr ().get_locus ());
    1133            2 :   r.add_range (expr.get_index_expr ().get_locus ());
    1134            2 :   rust_error_at (r, ErrorCode::E0277, "the type %qs cannot be indexed by %qs",
    1135            4 :                  array_expr_ty->get_name ().c_str (),
    1136            2 :                  index_expr_ty->get_name ().c_str ());
    1137            2 : }
    1138              : 
    1139              : void
    1140          433 : TypeCheckExpr::visit (HIR::ArrayExpr &expr)
    1141              : {
    1142          433 :   auto &elements = expr.get_internal_elements ();
    1143              : 
    1144          433 :   TyTy::BaseType *expected_ty = nullptr;
    1145          433 :   bool ok = context->lookup_builtin ("usize", &expected_ty);
    1146          433 :   rust_assert (ok);
    1147              : 
    1148          433 :   HIR::Expr *capacity_expr = nullptr;
    1149          433 :   TyTy::BaseType *element_type = nullptr;
    1150          433 :   TyTy::BaseType *capacity_type = nullptr;
    1151          433 :   switch (elements.get_array_expr_type ())
    1152              :     {
    1153          123 :     case HIR::ArrayElems::ArrayExprType::COPIED:
    1154          123 :       {
    1155          123 :         HIR::ArrayElemsCopied &elems
    1156              :           = static_cast<HIR::ArrayElemsCopied &> (elements);
    1157          123 :         element_type = TypeCheckExpr::Resolve (elems.get_elem_to_copy ());
    1158              : 
    1159          123 :         auto capacity_expr_ty
    1160          123 :           = TypeCheckExpr::Resolve (elems.get_num_copies_expr ());
    1161          123 :         if (capacity_expr_ty->is<TyTy::ErrorType> ())
    1162            7 :           return;
    1163              : 
    1164          120 :         context->insert_type (elems.get_num_copies_expr ().get_mappings (),
    1165              :                               expected_ty);
    1166              : 
    1167          240 :         auto result = unify_site (
    1168          120 :           expr.get_mappings ().get_hirid (), TyTy::TyWithLocation (expected_ty),
    1169              :           TyTy::TyWithLocation (capacity_expr_ty,
    1170          120 :                                 elems.get_num_copies_expr ().get_locus ()),
    1171              :           expr.get_locus ());
    1172          120 :         if (result->is<TyTy::ErrorType> ())
    1173              :           return;
    1174              : 
    1175          116 :         capacity_expr = &elems.get_num_copies_expr ();
    1176          116 :         capacity_type = expected_ty;
    1177              :       }
    1178          116 :       break;
    1179              : 
    1180          310 :     case HIR::ArrayElems::ArrayExprType::VALUES:
    1181          310 :       {
    1182          310 :         HIR::ArrayElemsValues &elems
    1183              :           = static_cast<HIR::ArrayElemsValues &> (elements);
    1184              : 
    1185          310 :         std::vector<TyTy::BaseType *> types;
    1186         1827 :         for (auto &elem : elems.get_values ())
    1187              :           {
    1188         1517 :             types.push_back (TypeCheckExpr::Resolve (*elem));
    1189              :           }
    1190              : 
    1191              :         // this is a LUB
    1192          310 :         element_type
    1193          310 :           = TyTy::TyVar::get_implicit_infer_var (expr.get_locus ()).get_tyty ();
    1194         1827 :         for (auto &type : types)
    1195              :           {
    1196         1517 :             element_type
    1197         1517 :               = unify_site (expr.get_mappings ().get_hirid (),
    1198         1517 :                             TyTy::TyWithLocation (element_type),
    1199         1517 :                             TyTy::TyWithLocation (type, type->get_locus ()),
    1200              :                             expr.get_locus ());
    1201              :           }
    1202              : 
    1203          310 :         auto crate_num = mappings.get_current_crate ();
    1204          310 :         Analysis::NodeMapping mapping (crate_num, UNKNOWN_NODEID,
    1205          310 :                                        mappings.get_next_hir_id (crate_num),
    1206          310 :                                        UNKNOWN_LOCAL_DEFID);
    1207          310 :         std::string capacity_str = std::to_string (elems.get_num_elements ());
    1208          310 :         capacity_expr = new HIR::LiteralExpr (mapping, capacity_str,
    1209              :                                               HIR::Literal::LitType::INT,
    1210              :                                               PrimitiveCoreType::CORETYPE_USIZE,
    1211          930 :                                               UNDEF_LOCATION, {});
    1212              : 
    1213              :         // mark the type for this implicit node
    1214          310 :         context->insert_type (mapping, expected_ty);
    1215          310 :         capacity_type = expected_ty;
    1216          310 :       }
    1217          310 :       break;
    1218              :     }
    1219              : 
    1220          426 :   rust_assert (capacity_expr);
    1221          426 :   rust_assert (capacity_type);
    1222          426 :   auto ctx = Compile::Context::get ();
    1223          426 :   tree capacity_value
    1224          426 :     = Compile::HIRCompileBase::query_compile_const_expr (ctx, capacity_type,
    1225              :                                                          *capacity_expr);
    1226              : 
    1227              :   // Create ConstValueType with ref == ty_ref (both pointing to capacity_expr)
    1228              :   // ty_ref gets updated during substitution via set_ty_ref()
    1229          426 :   HirId capacity_expr_id = capacity_expr->get_mappings ().get_hirid ();
    1230          426 :   auto const_type
    1231              :     = new TyTy::ConstValueType (capacity_value, expected_ty, capacity_expr_id,
    1232          426 :                                 capacity_expr_id);
    1233              : 
    1234              :   // Insert the ConstValueType at its ref
    1235          426 :   context->insert_type (capacity_expr->get_mappings (),
    1236          426 :                         const_type->as_base_type ());
    1237              : 
    1238          426 :   infered
    1239          852 :     = new TyTy::ArrayType (expr.get_mappings ().get_hirid (), expr.get_locus (),
    1240              :                            TyTy::TyVar (
    1241          426 :                              const_type->as_base_type ()->get_ty_ref ()),
    1242          852 :                            TyTy::TyVar (element_type->get_ref ()));
    1243              : }
    1244              : 
    1245              : // empty struct
    1246              : void
    1247           81 : TypeCheckExpr::visit (HIR::StructExprStruct &struct_expr)
    1248              : {
    1249           81 :   HIR::PathInExpression &path = struct_expr.get_struct_name ();
    1250              : 
    1251           81 :   TyTy::BaseType *struct_path_ty = TypeCheckExpr::Resolve (path);
    1252           81 :   if (struct_path_ty->get_kind () != TyTy::TypeKind::ADT)
    1253              :     {
    1254            0 :       rust_error_at (path.get_locus (), "expected an ADT type for constructor");
    1255            1 :       return;
    1256              :     }
    1257              : 
    1258           81 :   TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (struct_path_ty);
    1259           81 :   TyTy::VariantDef *variant;
    1260              : 
    1261              :   // unwrap and type check the variant if it's an enum
    1262           81 :   if (adt->is_enum ())
    1263              :     {
    1264            3 :       HirId variant_id;
    1265            3 :       bool ok = context->lookup_variant_definition (
    1266            3 :         struct_expr.get_struct_name ().get_mappings ().get_hirid (),
    1267              :         &variant_id);
    1268            3 :       if (!ok)
    1269              :         {
    1270            0 :           rich_location r (line_table, struct_expr.get_locus ());
    1271            0 :           r.add_range (struct_expr.get_struct_name ().get_locus ());
    1272            0 :           rust_error_at (
    1273            0 :             struct_expr.get_struct_name ().get_locus (), ErrorCode::E0574,
    1274              :             "expected a struct, variant or union type, found enum %qs",
    1275            0 :             adt->get_name ().c_str ());
    1276            0 :           return;
    1277            0 :         }
    1278              : 
    1279            3 :       ok = adt->lookup_variant_by_id (variant_id, &variant);
    1280            3 :       rust_assert (ok);
    1281              :     }
    1282              :   else
    1283              :     {
    1284           78 :       rust_assert (adt->number_of_variants () == 1);
    1285           78 :       variant = adt->get_variants ().at (0);
    1286              :     }
    1287              : 
    1288           81 :   if (!variant->get_fields ().empty ())
    1289              :     {
    1290            1 :       std::vector<std::string> field_names;
    1291            4 :       for (auto &field : variant->get_fields ())
    1292            3 :         field_names.push_back (field->get_name ());
    1293            1 :       Error missing_fields_error
    1294              :         = TypeCheckStructExpr::make_missing_field_error (
    1295            1 :           struct_expr.get_locus (), field_names, struct_path_ty->get_name ());
    1296              :       // We might want to return or handle these in the future emit for now.
    1297            1 :       missing_fields_error.emit ();
    1298            1 :       return;
    1299            1 :     }
    1300              : 
    1301           80 :   infered = struct_path_ty;
    1302              : }
    1303              : 
    1304              : void
    1305         1381 : TypeCheckExpr::visit (HIR::StructExprStructFields &struct_expr)
    1306              : {
    1307         1381 :   infered = TypeCheckStructExpr::Resolve (struct_expr);
    1308         1381 : }
    1309              : 
    1310              : void
    1311          314 : TypeCheckExpr::visit (HIR::GroupedExpr &expr)
    1312              : {
    1313          314 :   infered = TypeCheckExpr::Resolve (expr.get_expr_in_parens ());
    1314          314 : }
    1315              : 
    1316              : void
    1317         5059 : TypeCheckExpr::visit (HIR::FieldAccessExpr &expr)
    1318              : {
    1319         5059 :   auto struct_base = TypeCheckExpr::Resolve (expr.get_receiver_expr ());
    1320              : 
    1321              :   // Box<T> autoderef
    1322         5059 :   if (auto try_struct_base = TyTy::try_get_box_inner_type (struct_base))
    1323              :     {
    1324            1 :       struct_base = *try_struct_base;
    1325              :     }
    1326              : 
    1327              :   // FIXME does this require autoderef here?
    1328         5059 :   if (struct_base->get_kind () == TyTy::TypeKind::REF)
    1329              :     {
    1330         3466 :       TyTy::ReferenceType *r = static_cast<TyTy::ReferenceType *> (struct_base);
    1331         3466 :       struct_base = r->get_base ();
    1332              :     }
    1333              : 
    1334         5059 :   bool is_valid_type = struct_base->get_kind () == TyTy::TypeKind::ADT;
    1335         5059 :   if (!is_valid_type)
    1336              :     {
    1337            0 :       rust_error_at (expr.get_locus (), "expected algebraic data type got %qs",
    1338            0 :                      struct_base->get_name ().c_str ());
    1339            4 :       return;
    1340              :     }
    1341              : 
    1342         5059 :   TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (struct_base);
    1343         5059 :   rust_assert (adt->number_of_variants () > 0);
    1344         5059 :   TyTy::VariantDef *vaiant = adt->get_variants ().at (0);
    1345              : 
    1346         5059 :   TyTy::StructFieldType *lookup = nullptr;
    1347         5059 :   bool found = vaiant->lookup_field (expr.get_field_name ().as_string (),
    1348              :                                      &lookup, nullptr);
    1349         5059 :   if (!found || adt->is_enum ())
    1350              :     {
    1351            4 :       rich_location r (line_table, expr.get_locus ());
    1352            4 :       r.add_range (expr.get_field_name ().get_locus ());
    1353            4 :       rust_error_at (r, ErrorCode::E0609, "no field %qs on type %qs",
    1354            8 :                      expr.get_field_name ().as_string ().c_str (),
    1355            4 :                      adt->get_name ().c_str ());
    1356            4 :       return;
    1357            4 :     }
    1358              : 
    1359         5055 :   infered = lookup->get_field_type ();
    1360              : }
    1361              : 
    1362              : bool
    1363           43 : is_default_fn (const MethodCandidate &candidate)
    1364              : {
    1365           43 :   if (candidate.candidate.is_impl_candidate ())
    1366              :     {
    1367           43 :       auto *item = candidate.candidate.item.impl.impl_item;
    1368              : 
    1369           43 :       if (item->get_impl_item_type () == HIR::ImplItem::FUNCTION)
    1370              :         {
    1371           43 :           auto &fn = static_cast<HIR::Function &> (*item);
    1372              : 
    1373           43 :           return fn.is_default ();
    1374              :         }
    1375              :     }
    1376              : 
    1377              :   return false;
    1378              : }
    1379              : 
    1380              : void
    1381            2 : emit_ambiguous_resolution_error (HIR::MethodCallExpr &expr,
    1382              :                                  std::set<MethodCandidate> &candidates)
    1383              : {
    1384            2 :   rich_location r (line_table, expr.get_method_name ().get_locus ());
    1385            2 :   std::string rich_msg = "multiple "
    1386            6 :                          + expr.get_method_name ().get_segment ().to_string ()
    1387            2 :                          + " found";
    1388              : 
    1389              :   // We have to filter out default candidates
    1390            6 :   for (auto &c : candidates)
    1391            4 :     if (!is_default_fn (c))
    1392            4 :       r.add_range (c.candidate.locus);
    1393              : 
    1394            2 :   r.add_fixit_replace (rich_msg.c_str ());
    1395              : 
    1396            2 :   rust_error_at (r, ErrorCode::E0592, "duplicate definitions with name %qs",
    1397            6 :                  expr.get_method_name ().get_segment ().to_string ().c_str ());
    1398            2 : }
    1399              : 
    1400              : // We are allowed to have multiple candidates if they are all specializable
    1401              : // functions or if all of them except one are specializable functions.
    1402              : // In the later case, we just return a valid candidate without erroring out
    1403              : // about ambiguity. If there are two or more specialized functions, then we
    1404              : // error out.
    1405              : //
    1406              : // FIXME: The first case is not handled at the moment, so we error out
    1407              : tl::optional<const MethodCandidate &>
    1408           16 : handle_multiple_candidates (HIR::MethodCallExpr &expr,
    1409              :                             std::set<MethodCandidate> &candidates)
    1410              : {
    1411           16 :   auto all_default = true;
    1412           16 :   tl::optional<const MethodCandidate &> found = tl::nullopt;
    1413              : 
    1414           53 :   for (auto &c : candidates)
    1415              :     {
    1416           39 :       if (!is_default_fn (c))
    1417              :         {
    1418           18 :           all_default = false;
    1419              : 
    1420              :           // We haven't found a final candidate yet, so we can select
    1421              :           // this one. However, if we already have a candidate, then
    1422              :           // that means there are multiple non-default candidates - we
    1423              :           // must error out
    1424           18 :           if (!found)
    1425              :             {
    1426              :               found = c;
    1427              :             }
    1428              :           else
    1429              :             {
    1430            2 :               emit_ambiguous_resolution_error (expr, candidates);
    1431            2 :               return tl::nullopt;
    1432              :             }
    1433              :         }
    1434              :     }
    1435              : 
    1436              :   // None of the candidates were a non-default (specialized) function, so we
    1437              :   // error out
    1438           14 :   if (all_default)
    1439              :     {
    1440            0 :       rust_sorry_at (expr.get_locus (),
    1441              :                      "cannot resolve method calls to non-specialized methods "
    1442              :                      "(all function candidates are %qs)",
    1443              :                      "default");
    1444            0 :       return tl::nullopt;
    1445              :     }
    1446              : 
    1447           14 :   return found;
    1448              : }
    1449              : 
    1450              : void
    1451         3048 : TypeCheckExpr::visit (HIR::MethodCallExpr &expr)
    1452              : {
    1453         3048 :   auto receiver_tyty = TypeCheckExpr::Resolve (expr.get_receiver ());
    1454         3048 :   if (receiver_tyty->get_kind () == TyTy::TypeKind::ERROR)
    1455              :     {
    1456            1 :       rust_error_at (expr.get_receiver ().get_locus (),
    1457              :                      "failed to resolve receiver in MethodCallExpr");
    1458           12 :       return;
    1459              :     }
    1460              : 
    1461         3047 :   rust_debug_loc (expr.get_locus (), "attempting to resolve method for %s",
    1462         3047 :                   receiver_tyty->debug_str ().c_str ());
    1463         3047 :   auto candidates
    1464              :     = MethodResolver::Probe (receiver_tyty,
    1465         3047 :                              expr.get_method_name ().get_segment ());
    1466         3047 :   if (candidates.empty ())
    1467              :     {
    1468            7 :       rich_location richloc (line_table, expr.get_method_name ().get_locus ());
    1469            7 :       richloc.add_fixit_replace ("method not found");
    1470            7 :       rust_error_at (
    1471              :         richloc, ErrorCode::E0599,
    1472              :         "no method named %qs found in the current scope",
    1473           14 :         expr.get_method_name ().get_segment ().to_string ().c_str ());
    1474            7 :       return;
    1475            7 :     }
    1476              : 
    1477         3040 :   tl::optional<const MethodCandidate &> candidate = *candidates.begin ();
    1478              : 
    1479         3040 :   if (candidates.size () > 1)
    1480           16 :     candidate = handle_multiple_candidates (expr, candidates);
    1481              : 
    1482         3040 :   if (!candidate)
    1483              :     return;
    1484              : 
    1485         3038 :   auto found_candidate = *candidate;
    1486              : 
    1487         6076 :   rust_debug_loc (expr.get_method_name ().get_locus (),
    1488              :                   "resolved method to: {%u} {%s} with [%lu] adjustments",
    1489         3038 :                   found_candidate.candidate.ty->get_ref (),
    1490         3038 :                   found_candidate.candidate.ty->debug_str ().c_str (),
    1491         3038 :                   (unsigned long) found_candidate.adjustments.size ());
    1492              : 
    1493              :   // Get the adjusted self
    1494         3038 :   Adjuster adj (receiver_tyty);
    1495         3038 :   TyTy::BaseType *adjusted_self = adj.adjust_type (found_candidate.adjustments);
    1496         3038 :   rust_debug ("receiver: %s adjusted self %s",
    1497              :               receiver_tyty->debug_str ().c_str (),
    1498              :               adjusted_self->debug_str ().c_str ());
    1499              : 
    1500              :   // store the adjustments for code-generation to know what to do which must be
    1501              :   // stored onto the receiver to so as we don't trigger duplicate deref mappings
    1502              :   // ICE when an argument is a method call
    1503         3038 :   HirId autoderef_mappings_id
    1504         3038 :     = expr.get_receiver ().get_mappings ().get_hirid ();
    1505         3038 :   context->insert_autoderef_mappings (autoderef_mappings_id,
    1506              :                                       std::move (found_candidate.adjustments));
    1507              : 
    1508         3038 :   PathProbeCandidate &resolved_candidate = found_candidate.candidate;
    1509         3038 :   TyTy::BaseType *lookup_tyty = found_candidate.candidate.ty;
    1510         3038 :   NodeId resolved_node_id
    1511         3038 :     = resolved_candidate.is_impl_candidate ()
    1512         3038 :         ? resolved_candidate.item.impl.impl_item->get_impl_mappings ()
    1513         2071 :             .get_nodeid ()
    1514          967 :         : resolved_candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
    1515              : 
    1516         3038 :   if (lookup_tyty->get_kind () != TyTy::TypeKind::FNDEF)
    1517              :     {
    1518            0 :       rich_location r (line_table, expr.get_method_name ().get_locus ());
    1519            0 :       r.add_range (resolved_candidate.locus);
    1520            0 :       rust_error_at (r, "associated impl item is not a method");
    1521            0 :       return;
    1522            0 :     }
    1523              : 
    1524         3038 :   TyTy::BaseType *lookup = lookup_tyty;
    1525         3038 :   TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
    1526         6076 :   if (!fn->is_method ())
    1527              :     {
    1528            0 :       rich_location r (line_table, expr.get_method_name ().get_locus ());
    1529            0 :       r.add_range (resolved_candidate.locus);
    1530            0 :       rust_error_at (r, "associated function is not a method");
    1531            0 :       return;
    1532            0 :     }
    1533              : 
    1534         3038 :   rust_debug_loc (expr.get_locus (), "resolved method call to: {%u} {%s}",
    1535         3038 :                   found_candidate.candidate.ty->get_ref (),
    1536         3038 :                   found_candidate.candidate.ty->debug_str ().c_str ());
    1537              : 
    1538         3038 :   if (resolved_candidate.is_impl_candidate ())
    1539              :     {
    1540         2071 :       auto infer_arguments = TyTy::SubstitutionArgumentMappings::empty ();
    1541         2071 :       infer_arguments.get_mut_regions ()
    1542         2071 :         = fn->get_used_arguments ().get_regions ();
    1543         2071 :       HIR::ImplBlock &impl = *resolved_candidate.item.impl.parent;
    1544         2071 :       TyTy::BaseType *impl_self_infer
    1545         2071 :         = TypeCheckItem::ResolveImplBlockSelfWithInference (impl,
    1546              :                                                             expr.get_locus (),
    1547              :                                                             &infer_arguments);
    1548         2071 :       if (impl_self_infer->get_kind () == TyTy::TypeKind::ERROR)
    1549              :         {
    1550            0 :           rich_location r (line_table, expr.get_locus ());
    1551            0 :           r.add_range (impl.get_type ().get_locus ());
    1552            0 :           rust_error_at (
    1553              :             r, "failed to resolve impl type for method call resolution");
    1554            0 :           return;
    1555            0 :         }
    1556              : 
    1557         2071 :       if (!infer_arguments.is_empty ())
    1558          555 :         lookup = SubstMapperInternal::Resolve (lookup, infer_arguments);
    1559         2071 :     }
    1560              : 
    1561              :   // apply any remaining generic arguments
    1562         3038 :   if (expr.get_method_name ().has_generic_args ())
    1563              :     {
    1564           29 :       HIR::GenericArgs &args = expr.get_method_name ().get_generic_args ();
    1565           29 :       rust_debug_loc (args.get_locus (),
    1566              :                       "applying generic arguments to method_call: {%s}",
    1567           29 :                       lookup->debug_str ().c_str ());
    1568              : 
    1569           29 :       lookup
    1570           29 :         = SubstMapper::Resolve (lookup, expr.get_method_name ().get_locus (),
    1571              :                                 &args);
    1572           29 :       if (lookup->get_kind () == TyTy::TypeKind::ERROR)
    1573              :         return;
    1574              :     }
    1575         3009 :   else if (lookup->needs_generic_substitutions ())
    1576              :     {
    1577          873 :       rust_debug ("method needs inference: {%s}",
    1578              :                   lookup->debug_str ().c_str ());
    1579          873 :       lookup = SubstMapper::InferSubst (lookup,
    1580          873 :                                         expr.get_method_name ().get_locus ());
    1581              :     }
    1582              : 
    1583         3037 :   rust_debug ("type-checking method_call: {%s}", lookup->debug_str ().c_str ());
    1584              : 
    1585         3037 :   TyTy::BaseType *function_ret_tyty
    1586         3037 :     = TyTy::TypeCheckMethodCallExpr::go (static_cast<TyTy::FnType *> (lookup),
    1587              :                                          expr, adjusted_self, context);
    1588         3037 :   if (function_ret_tyty == nullptr
    1589         3037 :       || function_ret_tyty->get_kind () == TyTy::TypeKind::ERROR)
    1590              :     {
    1591            0 :       rust_error_at (expr.get_locus (),
    1592              :                      "failed to lookup type to MethodCallExpr");
    1593            0 :       return;
    1594              :     }
    1595              : 
    1596              :   // store the expected fntype
    1597         3037 :   context->insert_type (expr.get_method_name ().get_mappings (), lookup);
    1598              : 
    1599         3037 :   auto &nr_ctx = Resolver2_0::FinalizedNameResolutionContext::get ();
    1600              : 
    1601         3037 :   nr_ctx.map_usage (Resolver2_0::Usage (expr.get_mappings ().get_nodeid ()),
    1602         3037 :                     Resolver2_0::Definition (resolved_node_id),
    1603              :                     Resolver2_0::Namespace::Values);
    1604              : 
    1605              :   // return the result of the function back
    1606         3037 :   infered = function_ret_tyty;
    1607         3048 : }
    1608              : 
    1609              : void
    1610          137 : TypeCheckExpr::visit (HIR::LoopExpr &expr)
    1611              : {
    1612          137 :   context->push_new_loop_context (expr.get_mappings ().get_hirid (),
    1613              :                                   expr.get_locus ());
    1614          137 :   TyTy::BaseType *block_expr = TypeCheckExpr::Resolve (expr.get_loop_block ());
    1615          137 :   if (!block_expr->is_unit ())
    1616              :     {
    1617            0 :       rust_error_at (expr.get_loop_block ().get_locus (),
    1618              :                      "expected %<()%> got %s",
    1619            0 :                      block_expr->as_string ().c_str ());
    1620            0 :       return;
    1621              :     }
    1622              : 
    1623          137 :   TyTy::BaseType *loop_context_type = context->pop_loop_context ();
    1624              : 
    1625          137 :   bool loop_context_type_infered
    1626          137 :     = (loop_context_type->get_kind () != TyTy::TypeKind::INFER)
    1627          137 :       || ((loop_context_type->get_kind () == TyTy::TypeKind::INFER)
    1628          128 :           && (((TyTy::InferType *) loop_context_type)->get_infer_kind ()
    1629          258 :               != TyTy::InferType::GENERAL));
    1630              : 
    1631          137 :   infered = loop_context_type_infered ? loop_context_type
    1632          121 :                                       : TyTy::TupleType::get_unit_type ();
    1633              : }
    1634              : 
    1635              : void
    1636           84 : TypeCheckExpr::visit (HIR::WhileLoopExpr &expr)
    1637              : {
    1638           84 :   context->push_new_while_loop_context (expr.get_mappings ().get_hirid ());
    1639           84 :   TyTy::BaseType *predicate_type
    1640           84 :     = TypeCheckExpr::Resolve (expr.get_predicate_expr ());
    1641           84 :   if (predicate_type->get_kind () != TyTy::TypeKind::BOOL
    1642           84 :       && predicate_type->get_kind () != TyTy::TypeKind::NEVER)
    1643              :     {
    1644            0 :       rust_error_at (expr.get_predicate_expr ().get_locus (),
    1645              :                      "expected boolean expression in %<while%> condition");
    1646            0 :       context->pop_loop_context ();
    1647            0 :       return;
    1648              :     }
    1649           84 :   TyTy::BaseType *block_expr = TypeCheckExpr::Resolve (expr.get_loop_block ());
    1650           84 :   if (!block_expr->is_unit ())
    1651              :     {
    1652            0 :       rust_error_at (expr.get_loop_block ().get_locus (),
    1653              :                      "expected %<()%> got %s",
    1654            0 :                      block_expr->as_string ().c_str ());
    1655            0 :       context->pop_loop_context ();
    1656            0 :       return;
    1657              :     }
    1658           84 :   context->pop_loop_context ();
    1659           84 :   infered = TyTy::TupleType::get_unit_type ();
    1660              : }
    1661              : 
    1662              : void
    1663          105 : TypeCheckExpr::visit (HIR::BreakExpr &expr)
    1664              : {
    1665          105 :   if (!context->have_loop_context ())
    1666              :     {
    1667            2 :       rust_error_at (expr.get_locus (), ErrorCode::E0268,
    1668              :                      "%<break%> outside of a loop or labeled block");
    1669            2 :       return;
    1670              :     }
    1671              : 
    1672          103 :   if (expr.has_break_expr ())
    1673              :     {
    1674           23 :       TyTy::BaseType *break_expr_tyty
    1675           23 :         = TypeCheckExpr::Resolve (expr.get_expr ());
    1676              : 
    1677           23 :       TyTy::BaseType *loop_context = context->peek_loop_context ();
    1678           23 :       if (loop_context->get_kind () == TyTy::TypeKind::ERROR)
    1679              :         {
    1680            4 :           rust_error_at (
    1681              :             expr.get_locus (), ErrorCode::E0571,
    1682              :             "can only %<break%> with a value inside a %<loop%> block");
    1683            4 :           return;
    1684              :         }
    1685              : 
    1686           19 :       TyTy::BaseType *unified_ty
    1687           38 :         = unify_site (expr.get_mappings ().get_hirid (),
    1688           19 :                       TyTy::TyWithLocation (loop_context),
    1689              :                       TyTy::TyWithLocation (break_expr_tyty,
    1690           19 :                                             expr.get_expr ().get_locus ()),
    1691              :                       expr.get_locus ());
    1692           19 :       context->swap_head_loop_context (unified_ty);
    1693              :     }
    1694              : 
    1695           99 :   infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ());
    1696              : }
    1697              : 
    1698              : void
    1699           25 : TypeCheckExpr::visit (HIR::ContinueExpr &expr)
    1700              : {
    1701           25 :   if (!context->have_loop_context ())
    1702              :     {
    1703            3 :       rust_error_at (expr.get_locus (), ErrorCode::E0268,
    1704              :                      "%<continue%> outside of a loop");
    1705            3 :       return;
    1706              :     }
    1707           22 :   infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ());
    1708              : }
    1709              : 
    1710              : void
    1711         2030 : TypeCheckExpr::visit (HIR::BorrowExpr &expr)
    1712              : {
    1713         2030 :   TyTy::BaseType *resolved_base = TypeCheckExpr::Resolve (expr.get_expr ());
    1714         2030 :   if (resolved_base->is<TyTy::ErrorType> ())
    1715              :     return;
    1716              : 
    1717              :   // In Rust this is valid because of DST's
    1718              :   //
    1719              :   // fn test() {
    1720              :   //     let a:&str = "TEST 1";
    1721              :   //     let b:&str = &"TEST 2";
    1722              :   // }
    1723         2029 :   if (resolved_base->get_kind () == TyTy::TypeKind::REF)
    1724              :     {
    1725           43 :       const TyTy::ReferenceType *ref
    1726              :         = static_cast<const TyTy::ReferenceType *> (resolved_base);
    1727              : 
    1728              :       // this might end up being a more generic is_dyn object check but lets
    1729              :       // double check dyn traits type-layout first
    1730           43 :       if (ref->is_dyn_str_type ())
    1731              :         {
    1732            9 :           infered = resolved_base;
    1733            9 :           return;
    1734              :         }
    1735              :     }
    1736              : 
    1737         2020 :   if (expr.is_raw_borrow ())
    1738              :     {
    1739            4 :       infered = new TyTy::PointerType (expr.get_mappings ().get_hirid (),
    1740            4 :                                        TyTy::TyVar (resolved_base->get_ref ()),
    1741            8 :                                        expr.get_mut ());
    1742              : 
    1743            4 :       return;
    1744              :     }
    1745              : 
    1746         2016 :   infered = new TyTy::ReferenceType (expr.get_mappings ().get_hirid (),
    1747         2016 :                                      TyTy::TyVar (resolved_base->get_ref ()),
    1748         4032 :                                      expr.get_mut ());
    1749              : }
    1750              : 
    1751              : void
    1752         3919 : TypeCheckExpr::visit (HIR::DereferenceExpr &expr)
    1753              : {
    1754         3919 :   TyTy::BaseType *resolved_base = TypeCheckExpr::Resolve (expr.get_expr ());
    1755              : 
    1756         3919 :   rust_debug_loc (expr.get_locus (), "attempting deref operator overload");
    1757         3919 :   auto lang_item_type = LangItem::Kind::DEREF;
    1758         3919 :   bool operator_overloaded
    1759         3919 :     = resolve_operator_overload (lang_item_type, expr, resolved_base, nullptr);
    1760         3919 :   if (operator_overloaded)
    1761              :     {
    1762              :       // operator overloaded deref always refurns a reference type lets assert
    1763              :       // this
    1764           49 :       rust_assert (infered->get_kind () == TyTy::TypeKind::REF);
    1765           49 :       resolved_base = infered;
    1766              :     }
    1767              : 
    1768         3919 :   bool is_valid_type = resolved_base->get_kind () == TyTy::TypeKind::REF
    1769         3919 :                        || resolved_base->get_kind () == TyTy::TypeKind::POINTER;
    1770              : 
    1771         3919 :   auto try_owned_box = TyTy::try_get_box_inner_type (resolved_base);
    1772              : 
    1773         3919 :   if (!is_valid_type && !try_owned_box)
    1774              :     {
    1775            0 :       rust_error_at (expr.get_locus (), "expected reference type got %s",
    1776            0 :                      resolved_base->as_string ().c_str ());
    1777            0 :       return;
    1778              :     }
    1779              : 
    1780         3919 :   if (try_owned_box)
    1781              :     {
    1782            1 :       infered = (*try_owned_box)->clone ();
    1783              :     }
    1784         3918 :   else if (resolved_base->get_kind () == TyTy::TypeKind::REF)
    1785              :     {
    1786         3720 :       TyTy::ReferenceType *ref_base
    1787              :         = static_cast<TyTy::ReferenceType *> (resolved_base);
    1788         3720 :       infered = ref_base->get_base ()->clone ();
    1789              :     }
    1790              :   else
    1791              :     {
    1792          198 :       TyTy::PointerType *ref_base
    1793              :         = static_cast<TyTy::PointerType *> (resolved_base);
    1794          198 :       infered = ref_base->get_base ()->clone ();
    1795              :     }
    1796              : }
    1797              : 
    1798              : void
    1799         5292 : TypeCheckExpr::visit (HIR::TypeCastExpr &expr)
    1800              : {
    1801         5292 :   TyTy::BaseType *expr_to_convert
    1802         5292 :     = TypeCheckExpr::Resolve (expr.get_casted_expr ());
    1803         5292 :   TyTy::BaseType *tyty_to_convert_to
    1804         5292 :     = TypeCheckType::Resolve (expr.get_type_to_convert_to ());
    1805              : 
    1806         5292 :   TyTy::TyWithLocation from (expr_to_convert,
    1807         5292 :                              expr.get_casted_expr ().get_locus ());
    1808         5292 :   TyTy::TyWithLocation to (tyty_to_convert_to,
    1809         5292 :                            expr.get_type_to_convert_to ().get_locus ());
    1810         5292 :   infered = cast_site (expr.get_mappings ().get_hirid (), from, to,
    1811              :                        expr.get_locus ());
    1812         5292 : }
    1813              : 
    1814              : void
    1815         1108 : TypeCheckExpr::visit (HIR::MatchExpr &expr)
    1816              : {
    1817              :   // this needs to perform a least upper bound coercion on the blocks and then
    1818              :   // unify the scruintee and arms
    1819         1108 :   TyTy::BaseType *scrutinee_tyty
    1820         1108 :     = TypeCheckExpr::Resolve (expr.get_scrutinee_expr ());
    1821              : 
    1822              :   // https://github.com/Rust-GCC/gccrs/issues/3231#issuecomment-2462660048
    1823              :   // https://github.com/rust-lang/rust/blob/3d1dba830a564d1118361345d7ada47a05241f45/compiler/rustc_hir_typeck/src/_match.rs#L32-L36
    1824         1108 :   if (!expr.has_match_arms ())
    1825              :     {
    1826              :       // this is a special case where rustc returns !
    1827            5 :       TyTy::BaseType *lookup = nullptr;
    1828            5 :       bool ok = context->lookup_builtin ("!", &lookup);
    1829            5 :       rust_assert (ok);
    1830            5 :       infered = lookup->clone ();
    1831            5 :       return;
    1832              :     }
    1833              : 
    1834         1103 :   bool saw_error = false;
    1835         1103 :   std::vector<TyTy::BaseType *> kase_block_tys;
    1836         3666 :   for (auto &kase : expr.get_match_cases ())
    1837              :     {
    1838              :       // lets check the arms
    1839         2563 :       HIR::MatchArm &kase_arm = kase.get_arm ();
    1840         2563 :       auto &pattern = kase_arm.get_pattern ();
    1841         2563 :       TyTy::BaseType *kase_arm_ty
    1842         2563 :         = TypeCheckPattern::Resolve (*pattern, scrutinee_tyty);
    1843         2563 :       if (kase_arm_ty->get_kind () == TyTy ::TypeKind::ERROR)
    1844              :         {
    1845           12 :           saw_error = true;
    1846           12 :           continue;
    1847              :         }
    1848              : 
    1849         5102 :       TyTy::BaseType *checked_kase = unify_site (
    1850         2551 :         expr.get_mappings ().get_hirid (),
    1851              :         TyTy::TyWithLocation (scrutinee_tyty,
    1852         2551 :                               expr.get_scrutinee_expr ().get_locus ()),
    1853         2551 :         TyTy::TyWithLocation (kase_arm_ty, pattern->get_locus ()),
    1854              :         expr.get_locus ());
    1855         2551 :       if (checked_kase->get_kind () == TyTy::TypeKind::ERROR)
    1856              :         {
    1857            0 :           saw_error = true;
    1858            0 :           continue;
    1859              :         }
    1860              : 
    1861              :       // check the kase type
    1862         2551 :       TyTy::BaseType *kase_block_ty = TypeCheckExpr::Resolve (kase.get_expr ());
    1863         2551 :       kase_block_tys.push_back (kase_block_ty);
    1864              :     }
    1865         1103 :   if (saw_error)
    1866              :     return;
    1867              : 
    1868         1097 :   if (kase_block_tys.size () == 0)
    1869              :     {
    1870            0 :       infered = TyTy::TupleType::get_unit_type ();
    1871            0 :       return;
    1872              :     }
    1873              : 
    1874              :   // this is a LUB
    1875         1097 :   infered = kase_block_tys.at (0);
    1876         2544 :   for (size_t i = 1; i < kase_block_tys.size (); i++)
    1877              :     {
    1878         1447 :       TyTy::BaseType *kase_ty = kase_block_tys.at (i);
    1879         1447 :       infered
    1880         1447 :         = coercion_site (expr.get_mappings ().get_hirid (),
    1881         1447 :                          TyTy::TyWithLocation (infered),
    1882         1447 :                          TyTy::TyWithLocation (kase_ty), expr.get_locus ());
    1883              :     }
    1884         1103 : }
    1885              : 
    1886              : void
    1887           65 : TypeCheckExpr::visit (HIR::ClosureExpr &expr)
    1888              : {
    1889           65 :   std::vector<TyTy::SubstitutionParamMapping> subst_refs;
    1890           65 :   HirId ref = expr.get_mappings ().get_hirid ();
    1891           65 :   DefId id = expr.get_mappings ().get_defid ();
    1892           65 :   RustIdent ident{CanonicalPath::create_empty (), expr.get_locus ()};
    1893              : 
    1894           65 :   if (context->have_function_context ())
    1895              :     {
    1896           64 :       TypeCheckContextItem current_context = context->peek_context ();
    1897           64 :       TyTy::FnType *current_context_fndecl
    1898           64 :         = current_context.get_context_type ();
    1899              : 
    1900           64 :       ident = RustIdent{current_context_fndecl->get_ident ().path,
    1901           64 :                         expr.get_locus ()};
    1902              : 
    1903           64 :       subst_refs = current_context_fndecl->clone_substs ();
    1904              :     }
    1905              : 
    1906           65 :   std::vector<TyTy::TyVar> parameter_types;
    1907          125 :   for (auto &p : expr.get_params ())
    1908              :     {
    1909           60 :       TyTy::BaseType *param_tyty = nullptr;
    1910           60 :       if (p.has_type_given ())
    1911              :         {
    1912           58 :           param_tyty = TypeCheckType::Resolve (p.get_type ());
    1913              :         }
    1914              :       else
    1915              :         {
    1916            2 :           param_tyty = ClosureParamInfer::Resolve (p.get_pattern ());
    1917              :         }
    1918              : 
    1919           60 :       TyTy::TyVar param_ty (param_tyty->get_ref ());
    1920           60 :       parameter_types.push_back (param_ty);
    1921              : 
    1922           60 :       TypeCheckPattern::Resolve (p.get_pattern (), param_ty.get_tyty ());
    1923              :     }
    1924              : 
    1925              :   // we generate an implicit hirid for the closure args
    1926           65 :   HirId implicit_args_id = mappings.get_next_hir_id ();
    1927           65 :   TyTy::TupleType *closure_args
    1928              :     = new TyTy::TupleType (implicit_args_id, expr.get_locus (),
    1929           65 :                            parameter_types);
    1930           65 :   context->insert_implicit_type (closure_args->get_ref (), closure_args);
    1931              : 
    1932           65 :   location_t result_type_locus = expr.has_return_type ()
    1933           65 :                                    ? expr.get_return_type ().get_locus ()
    1934           65 :                                    : expr.get_locus ();
    1935           65 :   TyTy::TyVar result_type
    1936           65 :     = expr.has_return_type ()
    1937           65 :         ? TyTy::TyVar (
    1938              :           TypeCheckType::Resolve (expr.get_return_type ())->get_ref ())
    1939           65 :         : TyTy::TyVar::get_implicit_infer_var (expr.get_locus ());
    1940              : 
    1941              :   // resolve the block
    1942           65 :   location_t closure_expr_locus = expr.get_expr ().get_locus ();
    1943           65 :   TyTy::BaseType *closure_expr_ty = TypeCheckExpr::Resolve (expr.get_expr ());
    1944          130 :   coercion_site (expr.get_mappings ().get_hirid (),
    1945              :                  TyTy::TyWithLocation (result_type.get_tyty (),
    1946           65 :                                        result_type_locus),
    1947           65 :                  TyTy::TyWithLocation (closure_expr_ty, closure_expr_locus),
    1948              :                  expr.get_locus ());
    1949              : 
    1950              :   // generate the closure type
    1951           65 :   NodeId closure_node_id = expr.get_mappings ().get_nodeid ();
    1952              : 
    1953              :   // Resolve closure captures
    1954              : 
    1955           65 :   std::set<NodeId> captures;
    1956              : 
    1957           65 :   if (auto opt_cap
    1958           65 :       = Analysis::Mappings::get ().lookup_captures (closure_node_id))
    1959           42 :     for (auto cap : opt_cap.value ())
    1960           21 :       captures.insert (cap);
    1961              : 
    1962           65 :   infered = new TyTy::ClosureType (ref, id, ident, closure_args, result_type,
    1963          130 :                                    subst_refs, captures);
    1964              : 
    1965              :   // FIXME
    1966              :   // all closures automatically inherit the appropriate fn trait. Lets just
    1967              :   // assume FnOnce for now. I think this is based on the return type of the
    1968              :   // closure
    1969              : 
    1970           65 :   LangItem::Kind lang_item_type = LangItem::Kind::FN_ONCE;
    1971              : 
    1972           65 :   auto lang_item_defined = mappings.lookup_lang_item (lang_item_type);
    1973           65 :   if (!lang_item_defined)
    1974              :     {
    1975              :       // FIXME
    1976              :       // we need to have a unified way or error'ing when we are missing lang
    1977              :       // items that is useful
    1978            0 :       rust_fatal_error (expr.get_locus (), "unable to find lang item: %qs",
    1979            0 :                         LangItem::ToString (lang_item_type).c_str ());
    1980              :     }
    1981           65 :   DefId &respective_lang_item_id = lang_item_defined.value ();
    1982              : 
    1983              :   // these lang items are always traits
    1984           65 :   HIR::Item *item = mappings.lookup_defid (respective_lang_item_id).value ();
    1985           65 :   rust_assert (item->get_item_kind () == HIR::Item::ItemKind::Trait);
    1986           65 :   HIR::Trait *trait_item = static_cast<HIR::Trait *> (item);
    1987              : 
    1988           65 :   TraitReference *trait = TraitResolver::Resolve (*trait_item);
    1989           65 :   rust_assert (!trait->is_error ());
    1990              : 
    1991           65 :   TyTy::TypeBoundPredicate predicate (*trait, BoundPolarity::RegularBound,
    1992           65 :                                       expr.get_locus ());
    1993              : 
    1994              :   // resolve the trait bound where the <(Args)> are the parameter tuple type
    1995           65 :   HIR::GenericArgs args = HIR::GenericArgs::create_empty (expr.get_locus ());
    1996              : 
    1997              :   // lets generate an implicit Type so that it resolves to the implict tuple
    1998              :   // type we have created
    1999           65 :   auto crate_num = mappings.get_current_crate ();
    2000           65 :   Analysis::NodeMapping mapping (crate_num, expr.get_mappings ().get_nodeid (),
    2001           65 :                                  implicit_args_id, UNKNOWN_LOCAL_DEFID);
    2002           65 :   HIR::TupleType *implicit_tuple
    2003              :     = new HIR::TupleType (mapping,
    2004              :                           {} // we dont need to fill this out because it will
    2005              :                              // auto resolve because the hir id's match
    2006              :                           ,
    2007           65 :                           expr.get_locus ());
    2008           65 :   args.get_type_args ().emplace_back (implicit_tuple);
    2009              : 
    2010              :   // apply the arguments
    2011           65 :   predicate.apply_generic_arguments (&args, false, false);
    2012              : 
    2013              :   // finally inherit the trait bound
    2014          130 :   infered->inherit_bounds ({predicate});
    2015           65 : }
    2016              : 
    2017              : bool
    2018        12357 : TypeCheckExpr::resolve_operator_overload (
    2019              :   LangItem::Kind lang_item_type, HIR::OperatorExprMeta expr,
    2020              :   TyTy::BaseType *lhs, TyTy::BaseType *rhs,
    2021              :   HIR::PathIdentSegment specified_segment)
    2022              : {
    2023              :   // look up lang item for arithmetic type
    2024        12357 :   std::string associated_item_name = LangItem::ToString (lang_item_type);
    2025              : 
    2026        12357 :   auto lang_item_defined = mappings.lookup_lang_item (lang_item_type);
    2027              :   // probe for the lang-item
    2028        12357 :   if (!lang_item_defined)
    2029              :     return false;
    2030              : 
    2031         2716 :   DefId &respective_lang_item_id = lang_item_defined.value ();
    2032         2716 :   auto def_lookup = mappings.lookup_defid (respective_lang_item_id);
    2033         2716 :   rust_assert (def_lookup.has_value ());
    2034              : 
    2035         2716 :   HIR::Item *def_item = def_lookup.value ();
    2036         2716 :   rust_assert (def_item->get_item_kind () == HIR::Item::ItemKind::Trait);
    2037         2716 :   HIR::Trait &trait = *static_cast<HIR::Trait *> (def_item);
    2038         2716 :   TraitReference *defid_trait_reference = TraitResolver::Resolve (trait);
    2039         2716 :   rust_assert (!defid_trait_reference->is_error ());
    2040              : 
    2041              :   // we might be in a static or const context and unknown is fine
    2042         2716 :   TypeCheckContextItem current_context = TypeCheckContextItem::get_error ();
    2043         2716 :   if (context->have_function_context ())
    2044              :     {
    2045         2708 :       current_context = context->peek_context ();
    2046              :     }
    2047              : 
    2048         2716 :   auto segment = specified_segment.is_error ()
    2049         3730 :                    ? HIR::PathIdentSegment (associated_item_name)
    2050         2716 :                    : specified_segment;
    2051         2716 :   auto candidates = MethodResolver::Probe (lhs, segment);
    2052              : 
    2053              :   // remove any recursive candidates
    2054         2716 :   std::set<MethodCandidate> resolved_candidates;
    2055         5448 :   for (auto &c : candidates)
    2056              :     {
    2057         2732 :       const TyTy::BaseType *candidate_type = c.candidate.ty;
    2058         2732 :       rust_assert (candidate_type->get_kind () == TyTy::TypeKind::FNDEF);
    2059              : 
    2060         2732 :       const TyTy::FnType &fn
    2061              :         = *static_cast<const TyTy::FnType *> (candidate_type);
    2062              : 
    2063         2732 :       DefId current_fn_defid = current_context.get_defid ();
    2064         5464 :       bool recursive_candidated = fn.get_id () == current_fn_defid;
    2065         1537 :       if (!recursive_candidated)
    2066              :         {
    2067         1537 :           resolved_candidates.insert (c);
    2068              :         }
    2069              :     }
    2070              : 
    2071         2716 :   std::vector<TyTy::BaseType *> select_args = {};
    2072         2716 :   if (rhs != nullptr)
    2073         2490 :     select_args = {rhs};
    2074         2716 :   auto selected_candidates
    2075         2716 :     = MethodResolver::Select (resolved_candidates, lhs, select_args);
    2076              : 
    2077         2716 :   bool have_implementation_for_lang_item = selected_candidates.size () > 0;
    2078         2716 :   if (!have_implementation_for_lang_item)
    2079              :     return false;
    2080              : 
    2081         1422 :   if (selected_candidates.size () > 1)
    2082              :     {
    2083            8 :       auto infer
    2084            8 :         = TyTy::TyVar::get_implicit_infer_var (expr.get_locus ()).get_tyty ();
    2085            8 :       auto trait_subst = defid_trait_reference->get_trait_substs ();
    2086            8 :       rust_assert (trait_subst.size () > 0);
    2087              : 
    2088            8 :       TyTy::TypeBoundPredicate pred (respective_lang_item_id, trait_subst,
    2089              :                                      BoundPolarity::RegularBound,
    2090            8 :                                      expr.get_locus ());
    2091              : 
    2092            8 :       std::vector<TyTy::SubstitutionArg> mappings;
    2093            8 :       auto &self_param_mapping = trait_subst[0];
    2094            8 :       mappings.emplace_back (&self_param_mapping, lhs);
    2095              : 
    2096            8 :       if (rhs != nullptr)
    2097              :         {
    2098            8 :           rust_assert (trait_subst.size () == 2);
    2099            8 :           auto &rhs_param_mapping = trait_subst[1];
    2100            8 :           mappings.emplace_back (&rhs_param_mapping, lhs);
    2101              :         }
    2102              : 
    2103            8 :       std::map<std::string, TyTy::BaseType *> binding_args;
    2104            8 :       binding_args["Output"] = infer;
    2105              : 
    2106            8 :       TyTy::SubstitutionArgumentMappings arg_mappings (mappings, binding_args,
    2107            8 :                                                        TyTy::RegionParamList (
    2108            8 :                                                          trait_subst.size ()),
    2109           16 :                                                        expr.get_locus ());
    2110            8 :       pred.apply_argument_mappings (arg_mappings, false);
    2111              : 
    2112           16 :       infer->inherit_bounds ({pred});
    2113           16 :       DeferredOpOverload defer (expr.get_mappings ().get_hirid (),
    2114           16 :                                 lang_item_type, specified_segment, pred, expr);
    2115            8 :       context->insert_deferred_operator_overload (std::move (defer));
    2116              : 
    2117            8 :       if (rhs != nullptr)
    2118           16 :         lhs = unify_site (expr.get_mappings ().get_hirid (),
    2119            8 :                           TyTy::TyWithLocation (lhs),
    2120            8 :                           TyTy::TyWithLocation (rhs), expr.get_locus ());
    2121              : 
    2122           16 :       infered = unify_site (expr.get_mappings ().get_hirid (),
    2123            8 :                             TyTy::TyWithLocation (lhs),
    2124            8 :                             TyTy::TyWithLocation (infer), expr.get_locus ());
    2125            8 :       return true;
    2126            8 :     }
    2127              : 
    2128              :   // Get the adjusted self
    2129         1414 :   MethodCandidate candidate = *selected_candidates.begin ();
    2130         1414 :   Adjuster adj (lhs);
    2131         1414 :   TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments);
    2132              : 
    2133              :   // store the adjustments for code-generation to know what to do
    2134         1414 :   context->insert_autoderef_mappings (expr.get_lvalue_mappings ().get_hirid (),
    2135              :                                       std::move (candidate.adjustments));
    2136              : 
    2137         1414 :   PathProbeCandidate &resolved_candidate = candidate.candidate;
    2138         1414 :   TyTy::BaseType *lookup_tyty = candidate.candidate.ty;
    2139         1414 :   NodeId resolved_node_id
    2140         1414 :     = resolved_candidate.is_impl_candidate ()
    2141         1414 :         ? resolved_candidate.item.impl.impl_item->get_impl_mappings ()
    2142         1012 :             .get_nodeid ()
    2143          402 :         : resolved_candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
    2144              : 
    2145         1414 :   rust_assert (lookup_tyty->get_kind () == TyTy::TypeKind::FNDEF);
    2146         1414 :   TyTy::BaseType *lookup = lookup_tyty;
    2147         1414 :   TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
    2148         2828 :   rust_assert (fn->is_method ());
    2149              : 
    2150         1816 :   rust_debug ("is_impl_item_candidate: %s",
    2151              :               resolved_candidate.is_impl_candidate () ? "true" : "false");
    2152              : 
    2153              :   // in the case where we resolve to a trait bound we have to be careful we are
    2154              :   // able to do so there is a case where we are currently resolving the deref
    2155              :   // operator overload function which is generic and this might resolve to the
    2156              :   // trait item of deref which is not valid as its just another recursive case
    2157         1414 :   if (current_context.get_type () == TypeCheckContextItem::ItemType::IMPL_ITEM)
    2158              :     {
    2159          771 :       auto &impl_item = current_context.get_impl_item ();
    2160          771 :       HIR::ImplBlock *parent = impl_item.first;
    2161          771 :       HIR::Function *fn = impl_item.second;
    2162              : 
    2163          771 :       bool is_deref = lang_item_type == LangItem::Kind::DEREF
    2164          771 :                       || lang_item_type == LangItem::Kind::DEREF_MUT;
    2165         3084 :       bool is_deref_match = fn->get_function_name ().as_string ().compare (
    2166         1542 :                               LangItem::ToString (LangItem::Kind::DEREF))
    2167              :                               == 0
    2168         2167 :                             || fn->get_function_name ().as_string ().compare (
    2169         1396 :                                  LangItem::ToString (LangItem::Kind::DEREF_MUT))
    2170              :                                  == 0;
    2171              : 
    2172          771 :       bool is_recursive_op
    2173         1542 :         = fn->get_function_name ().as_string ().compare (associated_item_name)
    2174              :             == 0
    2175          771 :           || (is_deref && is_deref_match);
    2176          771 :       if (parent->has_trait_ref () && is_recursive_op)
    2177              :         {
    2178          335 :           TraitReference *trait_reference
    2179          335 :             = TraitResolver::Lookup (parent->get_trait_ref ());
    2180          335 :           if (!trait_reference->is_error ())
    2181              :             {
    2182          335 :               TyTy::BaseType *lookup = nullptr;
    2183          335 :               bool ok = context->lookup_type (fn->get_mappings ().get_hirid (),
    2184              :                                               &lookup);
    2185          335 :               rust_assert (ok);
    2186          335 :               rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
    2187              : 
    2188          335 :               TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup);
    2189          670 :               rust_assert (fntype->is_method ());
    2190              : 
    2191          335 :               bool is_lang_item_impl
    2192          335 :                 = trait_reference->get_mappings ().get_defid ()
    2193          337 :                     == respective_lang_item_id
    2194            2 :                   || (is_deref && is_deref_match);
    2195          335 :               bool self_is_lang_item_self
    2196          335 :                 = fntype->get_self_type ()->is_equal (*adjusted_self);
    2197          335 :               bool recursive_operator_overload
    2198              :                 = is_lang_item_impl && self_is_lang_item_self;
    2199              : 
    2200          335 :               if (recursive_operator_overload)
    2201          150 :                 return false;
    2202              :             }
    2203              :         }
    2204              :     }
    2205              : 
    2206              :   // we found a valid operator overload
    2207         1264 :   rust_debug_loc (expr.get_locus (), "resolved operator overload to: {%u} {%s}",
    2208         1264 :                   candidate.candidate.ty->get_ref (),
    2209         1264 :                   candidate.candidate.ty->debug_str ().c_str ());
    2210              : 
    2211              :   // handle generics
    2212         1264 :   if (lookup->needs_generic_substitutions ())
    2213          381 :     lookup = SubstMapper::InferSubst (lookup, expr.get_locus ());
    2214              : 
    2215              :   // type check the arguments if required
    2216         1264 :   TyTy::FnType *type = static_cast<TyTy::FnType *> (lookup);
    2217         1264 :   rust_assert (type->num_params () > 0);
    2218         1264 :   auto &fnparam = type->param_at (0);
    2219              : 
    2220              :   // typecheck the self
    2221         2528 :   unify_site (expr.get_mappings ().get_hirid (),
    2222         1264 :               TyTy::TyWithLocation (fnparam.get_type ()),
    2223         1264 :               TyTy::TyWithLocation (adjusted_self), expr.get_locus ());
    2224         1264 :   if (rhs == nullptr)
    2225              :     {
    2226           63 :       rust_assert (type->num_params () == 1);
    2227              :     }
    2228              :   else
    2229              :     {
    2230         1201 :       rust_assert (type->num_params () == 2);
    2231         1201 :       auto &fnparam = type->param_at (1);
    2232         2402 :       unify_site (expr.get_mappings ().get_hirid (),
    2233         1201 :                   TyTy::TyWithLocation (fnparam.get_type ()),
    2234         1201 :                   TyTy::TyWithLocation (rhs), expr.get_locus ());
    2235              :     }
    2236              : 
    2237         1264 :   rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
    2238         1264 :   fn = static_cast<TyTy::FnType *> (lookup);
    2239         1264 :   fn->monomorphize ();
    2240              : 
    2241              :   // get the return type
    2242         1264 :   TyTy::BaseType *function_ret_tyty
    2243         1264 :     = type->get_return_type ()->monomorphized_clone ();
    2244              : 
    2245              :   // store the expected fntype
    2246         1264 :   context->insert_operator_overload (expr.get_mappings ().get_hirid (), type);
    2247              : 
    2248              :   // set up the resolved name on the path
    2249         1264 :   auto &nr_ctx = Resolver2_0::FinalizedNameResolutionContext::get ();
    2250              : 
    2251         1264 :   nr_ctx.map_usage (Resolver2_0::Usage (expr.get_mappings ().get_nodeid ()),
    2252         1264 :                     Resolver2_0::Definition (resolved_node_id),
    2253              :                     Resolver2_0::Namespace::Types);
    2254              : 
    2255              :   // return the result of the function back
    2256         1264 :   infered = function_ret_tyty;
    2257              : 
    2258         1264 :   return true;
    2259         4130 : }
    2260              : 
    2261              : HIR::PathIdentSegment
    2262        10860 : TypeCheckExpr::resolve_possible_fn_trait_call_method_name (
    2263              :   const TyTy::BaseType &receiver,
    2264              :   TyTy::TypeBoundPredicate *associated_predicate)
    2265              : {
    2266              :   // FIXME
    2267              :   // the logic to map the FnTrait to their respective call trait-item is
    2268              :   // duplicated over in the backend/rust-compile-expr.cc
    2269        10887 :   for (const auto &bound : receiver.get_specified_bounds ())
    2270              :     {
    2271           93 :       bool found_fn = bound.get_name ().compare ("Fn") == 0;
    2272           93 :       bool found_fn_mut = bound.get_name ().compare ("FnMut") == 0;
    2273           93 :       bool found_fn_once = bound.get_name ().compare ("FnOnce") == 0;
    2274              : 
    2275           93 :       if (found_fn)
    2276              :         {
    2277            0 :           *associated_predicate = bound;
    2278            0 :           return HIR::PathIdentSegment ("call");
    2279              :         }
    2280           93 :       else if (found_fn_mut)
    2281              :         {
    2282            0 :           *associated_predicate = bound;
    2283            0 :           return HIR::PathIdentSegment ("call_mut");
    2284              :         }
    2285           93 :       else if (found_fn_once)
    2286              :         {
    2287           66 :           *associated_predicate = bound;
    2288           66 :           return HIR::PathIdentSegment ("call_once");
    2289              :         }
    2290              :     }
    2291              : 
    2292        10794 :   if (receiver.is<TyTy::ReferenceType> ())
    2293              :     {
    2294            0 :       const auto &ref = static_cast<const TyTy::ReferenceType &> (receiver);
    2295            0 :       const auto &underlying = *ref.get_base ();
    2296            0 :       for (const auto &bound : underlying.get_specified_bounds ())
    2297              :         {
    2298            0 :           bool found_fn = bound.get_name ().compare ("Fn") == 0;
    2299            0 :           bool found_fn_mut = bound.get_name ().compare ("FnMut") == 0;
    2300            0 :           bool found_fn_once = bound.get_name ().compare ("FnOnce") == 0;
    2301              : 
    2302            0 :           if (found_fn)
    2303              :             {
    2304            0 :               *associated_predicate = bound;
    2305            0 :               return HIR::PathIdentSegment ("call");
    2306              :             }
    2307            0 :           else if (found_fn_mut)
    2308              :             {
    2309            0 :               *associated_predicate = bound;
    2310            0 :               return HIR::PathIdentSegment ("call_mut");
    2311              :             }
    2312            0 :           else if (found_fn_once)
    2313              :             {
    2314            0 :               *associated_predicate = bound;
    2315            0 :               return HIR::PathIdentSegment ("call_once");
    2316              :             }
    2317              :         }
    2318              :     }
    2319              : 
    2320              :   // nothing
    2321        10794 :   *associated_predicate = TyTy::TypeBoundPredicate::error ();
    2322        10794 :   return HIR::PathIdentSegment ("");
    2323              : }
    2324              : 
    2325              : bool
    2326        10860 : TypeCheckExpr::resolve_fn_trait_call (HIR::CallExpr &expr,
    2327              :                                       TyTy::BaseType *receiver_tyty,
    2328              :                                       TyTy::BaseType **result)
    2329              : {
    2330              :   // we turn this into a method call expr
    2331              :   // TODO: add implicit self argument (?)
    2332        10860 :   auto associated_predicate = TyTy::TypeBoundPredicate::error ();
    2333        10860 :   HIR::PathIdentSegment method_name
    2334              :     = resolve_possible_fn_trait_call_method_name (*receiver_tyty,
    2335        10860 :                                                   &associated_predicate);
    2336        10860 :   if (method_name.is_error () || associated_predicate.is_error ())
    2337              :     return false;
    2338              : 
    2339           66 :   auto candidates = MethodResolver::Probe (receiver_tyty, method_name);
    2340           66 :   if (candidates.empty ())
    2341              :     return false;
    2342              : 
    2343           66 :   if (candidates.size () > 1)
    2344              :     {
    2345            0 :       rich_location r (line_table, expr.get_locus ());
    2346            0 :       for (auto &c : candidates)
    2347            0 :         r.add_range (c.candidate.locus);
    2348              : 
    2349            0 :       rust_error_at (
    2350              :         r, "multiple candidates found for function trait method call %qs",
    2351            0 :         method_name.to_string ().c_str ());
    2352            0 :       return false;
    2353            0 :     }
    2354              : 
    2355              :   // FnOnce::Output is normalized lazily by normalize_projection's closure
    2356              :   // special-case; no explicit setup is required here.
    2357              : 
    2358           66 :   auto candidate = *candidates.begin ();
    2359           66 :   rust_debug_loc (expr.get_locus (),
    2360              :                   "resolved call-expr to fn trait: {%u} {%s}",
    2361           66 :                   candidate.candidate.ty->get_ref (),
    2362           66 :                   candidate.candidate.ty->debug_str ().c_str ());
    2363              : 
    2364              :   // Get the adjusted self
    2365           66 :   Adjuster adj (receiver_tyty);
    2366           66 :   TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments);
    2367              : 
    2368              :   // store the adjustments for code-generation to know what to do which must be
    2369              :   // stored onto the receiver to so as we don't trigger duplicate deref mappings
    2370              :   // ICE when an argument is a method call
    2371           66 :   HIR::Expr &fnexpr = expr.get_fnexpr ();
    2372           66 :   HirId autoderef_mappings_id = fnexpr.get_mappings ().get_hirid ();
    2373           66 :   context->insert_autoderef_mappings (autoderef_mappings_id,
    2374              :                                       std::move (candidate.adjustments));
    2375              : 
    2376           66 :   PathProbeCandidate &resolved_candidate = candidate.candidate;
    2377           66 :   TyTy::BaseType *lookup_tyty = candidate.candidate.ty;
    2378           66 :   NodeId resolved_node_id
    2379           66 :     = resolved_candidate.is_impl_candidate ()
    2380           66 :         ? resolved_candidate.item.impl.impl_item->get_impl_mappings ()
    2381            0 :             .get_nodeid ()
    2382           66 :         : resolved_candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
    2383              : 
    2384           66 :   if (lookup_tyty->get_kind () != TyTy::TypeKind::FNDEF)
    2385              :     {
    2386            0 :       rich_location r (line_table, expr.get_locus ());
    2387            0 :       r.add_range (resolved_candidate.locus);
    2388            0 :       rust_error_at (r, "associated impl item is not a method");
    2389            0 :       return false;
    2390            0 :     }
    2391              : 
    2392           66 :   TyTy::BaseType *lookup = lookup_tyty;
    2393           66 :   TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
    2394          132 :   if (!fn->is_method ())
    2395              :     {
    2396            0 :       rich_location r (line_table, expr.get_locus ());
    2397            0 :       r.add_range (resolved_candidate.locus);
    2398            0 :       rust_error_at (r, "associated function is not a method");
    2399            0 :       return false;
    2400            0 :     }
    2401              : 
    2402              :   // fn traits only support tuple argument passing so we need to implicitly set
    2403              :   // this up to get the same type checking we get in the rest of the pipeline
    2404              : 
    2405           66 :   std::vector<TyTy::TyVar> call_args;
    2406          132 :   for (auto &arg : expr.get_arguments ())
    2407              :     {
    2408           66 :       TyTy::BaseType *a = TypeCheckExpr::Resolve (*arg);
    2409           66 :       call_args.emplace_back (a->get_ref ());
    2410              :     }
    2411              : 
    2412              :   // crate implicit tuple
    2413           66 :   HirId implicit_arg_id = mappings.get_next_hir_id ();
    2414           66 :   Analysis::NodeMapping mapping (mappings.get_current_crate (), UNKNOWN_NODEID,
    2415           66 :                                  implicit_arg_id, UNKNOWN_LOCAL_DEFID);
    2416              : 
    2417           66 :   TyTy::TupleType *tuple
    2418           66 :     = new TyTy::TupleType (implicit_arg_id, expr.get_locus (), call_args);
    2419           66 :   context->insert_implicit_type (implicit_arg_id, tuple);
    2420              : 
    2421           66 :   std::vector<TyTy::Argument> args;
    2422           66 :   args.emplace_back (mapping, tuple,
    2423           66 :                      expr.get_locus () /*FIXME is there a better location*/);
    2424              : 
    2425           66 :   TyTy::BaseType *function_ret_tyty
    2426           66 :     = TyTy::TypeCheckMethodCallExpr::go (fn, expr.get_mappings (), args,
    2427              :                                          expr.get_locus (), expr.get_locus (),
    2428              :                                          adjusted_self, context);
    2429           66 :   if (function_ret_tyty == nullptr
    2430           66 :       || function_ret_tyty->get_kind () == TyTy::TypeKind::ERROR)
    2431              :     {
    2432            0 :       rust_error_at (expr.get_locus (),
    2433              :                      "failed check fn trait call-expr MethodCallExpr");
    2434            0 :       return false;
    2435              :     }
    2436              : 
    2437              :   // store the expected fntype
    2438           66 :   context->insert_operator_overload (expr.get_mappings ().get_hirid (), fn);
    2439              : 
    2440              :   // set up the resolved name on the path
    2441           66 :   auto &nr_ctx = Resolver2_0::FinalizedNameResolutionContext::get ();
    2442              : 
    2443              :   // TODO: What namespace to use for inserting and looking up here? It's a trait
    2444              :   // call, so NS::Types is right?
    2445              : 
    2446           66 :   auto existing = nr_ctx.lookup (expr.get_mappings ().get_nodeid (),
    2447              :                                  Resolver2_0::Namespace::Types);
    2448           66 :   if (existing)
    2449            9 :     rust_assert (*existing == resolved_node_id);
    2450              :   else
    2451           57 :     nr_ctx.map_usage (Resolver2_0::Usage (expr.get_mappings ().get_nodeid ()),
    2452           57 :                       Resolver2_0::Definition (resolved_node_id),
    2453              :                       Resolver2_0::Namespace::Types);
    2454              : 
    2455              :   // return the result of the function back
    2456           66 :   auto mono = function_ret_tyty->monomorphized_clone ();
    2457           66 :   *result = mono;
    2458              : 
    2459           66 :   return true;
    2460        11058 : }
    2461              : 
    2462              : bool
    2463         7858 : TypeCheckExpr::validate_arithmetic_type (
    2464              :   const TyTy::BaseType *tyty, HIR::ArithmeticOrLogicalExpr::ExprType expr_type)
    2465              : {
    2466         7858 :   auto type = tyty->destructure ();
    2467         7858 :   if (type->get_kind () == TyTy::TypeKind::CONST)
    2468              :     {
    2469           15 :       auto base_const = type->as_const_type ();
    2470           15 :       type = base_const->get_specified_type ();
    2471              :     }
    2472              : 
    2473              :   // https://doc.rust-lang.org/reference/expressions/operator-expr.html#arithmetic-and-logical-binary-operators
    2474              :   // this will change later when traits are added
    2475         7858 :   switch (expr_type)
    2476              :     {
    2477         6678 :     case ArithmeticOrLogicalOperator::ADD:
    2478         6678 :     case ArithmeticOrLogicalOperator::SUBTRACT:
    2479         6678 :     case ArithmeticOrLogicalOperator::MULTIPLY:
    2480         6678 :     case ArithmeticOrLogicalOperator::DIVIDE:
    2481         6678 :     case ArithmeticOrLogicalOperator::MODULUS:
    2482         6678 :       return (type->get_kind () == TyTy::TypeKind::INT)
    2483         5082 :              || (type->get_kind () == TyTy::TypeKind::UINT)
    2484         4236 :              || (type->get_kind () == TyTy::TypeKind::FLOAT)
    2485         3852 :              || (type->get_kind () == TyTy::TypeKind::USIZE)
    2486         3234 :              || (type->get_kind () == TyTy::TypeKind::ISIZE)
    2487         3166 :              || (type->get_kind () == TyTy::TypeKind::INFER
    2488         3163 :                  && (((const TyTy::InferType *) type)->get_infer_kind ()
    2489              :                      == TyTy::InferType::INTEGRAL))
    2490         6718 :              || (type->get_kind () == TyTy::TypeKind::INFER
    2491           37 :                  && (((const TyTy::InferType *) type)->get_infer_kind ()
    2492              :                      == TyTy::InferType::FLOAT));
    2493              : 
    2494              :       // integers or bools
    2495         1014 :     case ArithmeticOrLogicalOperator::BITWISE_AND:
    2496         1014 :     case ArithmeticOrLogicalOperator::BITWISE_OR:
    2497         1014 :     case ArithmeticOrLogicalOperator::BITWISE_XOR:
    2498         1014 :       return (type->get_kind () == TyTy::TypeKind::INT)
    2499          965 :              || (type->get_kind () == TyTy::TypeKind::UINT)
    2500          171 :              || (type->get_kind () == TyTy::TypeKind::USIZE)
    2501          164 :              || (type->get_kind () == TyTy::TypeKind::ISIZE)
    2502          164 :              || (type->get_kind () == TyTy::TypeKind::BOOL)
    2503         1136 :              || (type->get_kind () == TyTy::TypeKind::INFER
    2504          122 :                  && (((const TyTy::InferType *) type)->get_infer_kind ()
    2505              :                      == TyTy::InferType::INTEGRAL));
    2506              : 
    2507              :       // integers only
    2508          166 :     case ArithmeticOrLogicalOperator::LEFT_SHIFT:
    2509          166 :     case ArithmeticOrLogicalOperator::RIGHT_SHIFT:
    2510          166 :       return (type->get_kind () == TyTy::TypeKind::INT)
    2511          151 :              || (type->get_kind () == TyTy::TypeKind::UINT)
    2512           93 :              || (type->get_kind () == TyTy::TypeKind::USIZE)
    2513           91 :              || (type->get_kind () == TyTy::TypeKind::ISIZE)
    2514          257 :              || (type->get_kind () == TyTy::TypeKind::INFER
    2515           91 :                  && (((const TyTy::InferType *) type)->get_infer_kind ()
    2516              :                      == TyTy::InferType::INTEGRAL));
    2517              :     }
    2518              : 
    2519            0 :   rust_unreachable ();
    2520              :   return false;
    2521              : }
    2522              : 
    2523              : } // namespace Resolver
    2524              : } // 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.