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

Generated by: LCOV version 2.5.0-beta

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