LCOV - code coverage report
Current view: top level - gcc/rust/typecheck - rust-hir-type-check-expr.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 87.9 % 1360 1195
Test Date: 2026-10-03 16:17:38 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       161159 : TypeCheckExpr::TypeCheckExpr () : TypeCheckBase (), infered (nullptr) {}
      46              : 
      47              : TyTy::BaseType *
      48       161144 : TypeCheckExpr::Resolve (HIR::Expr &expr)
      49              : {
      50       161144 :   TypeCheckExpr resolver;
      51       161144 :   expr.accept_vis (resolver);
      52              : 
      53       161140 :   if (resolver.infered == nullptr)
      54           97 :     return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
      55              : 
      56       161043 :   if (resolver.infered->get_kind () != TyTy::TypeKind::CONST)
      57              :     {
      58       160898 :       auto ref = expr.get_mappings ().get_hirid ();
      59       160898 :       resolver.infered->set_ref (ref);
      60              :     }
      61       161043 :   resolver.context->insert_type (expr.get_mappings (), resolver.infered);
      62              : 
      63       161043 :   if (auto fn = resolver.infered->try_as<const TyTy::FnType> ())
      64              :     {
      65        11658 :       if (fn->is_syn_constant ())
      66           28 :         resolver.infered = fn->get_return_type ();
      67              :     }
      68              : 
      69       161043 :   return resolver.infered;
      70       161140 : }
      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          921 : TypeCheckExpr::visit (HIR::TupleIndexExpr &expr)
      88              : {
      89          921 :   auto resolved
      90          921 :     = TypeCheckExpr::Resolve (expr.get_tuple_expr ())->destructure ();
      91          921 :   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          919 :   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          919 :   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          919 :   bool is_valid_type = resolved->get_kind () == TyTy::TypeKind::ADT
     112          919 :                        || 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          917 :   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          758 :   TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (resolved);
     146          758 :   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          754 :   rust_assert (adt->number_of_variants () == 1);
     154              : 
     155          754 :   TyTy::VariantDef *variant = adt->get_variants ().at (0);
     156          754 :   TupleIndex index = expr.get_tuple_index ();
     157          754 :   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          754 :   auto field_tyty = variant->get_field_at_index ((size_t) index);
     164          754 :   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          754 :   infered = field_tyty->get_field_type ();
     172              : }
     173              : 
     174              : void
     175          635 : TypeCheckExpr::visit (HIR::TupleExpr &expr)
     176              : {
     177          635 :   if (expr.is_unit ())
     178              :     {
     179          152 :       infered = TyTy::TupleType::get_unit_type ();
     180          152 :       return;
     181              :     }
     182              : 
     183          483 :   std::vector<TyTy::TyVar> fields;
     184         1579 :   for (auto &elem : expr.get_tuple_elems ())
     185              :     {
     186         1096 :       auto field_ty = TypeCheckExpr::Resolve (*elem);
     187         1096 :       fields.emplace_back (field_ty->get_ref ());
     188              :     }
     189          966 :   infered = new TyTy::TupleType (expr.get_mappings ().get_hirid (),
     190          966 :                                  expr.get_locus (), fields);
     191          483 : }
     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          573 : TypeCheckExpr::visit (HIR::ReturnExpr &expr)
     251              : {
     252          573 :   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          572 :   auto fn_return_tyty = context->peek_return_type ();
     261          572 :   location_t expr_locus = expr.has_return_expr ()
     262          572 :                             ? 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          572 :   TyTy::BaseType *expr_ty;
     274          572 :   if (expr.has_return_expr ())
     275              :     {
     276          535 :       context->push_expected_type (fn_return_tyty);
     277          535 :       expr_ty = TypeCheckExpr::Resolve (expr.get_expr ());
     278          535 :       context->pop_expected_type ();
     279              :     }
     280              :   else
     281           37 :     expr_ty = TyTy::TupleType::get_unit_type ();
     282              : 
     283         1144 :   coercion_site (expr.get_mappings ().get_hirid (),
     284          572 :                  TyTy::TyWithLocation (fn_return_tyty),
     285          572 :                  TyTy::TyWithLocation (expr_ty, expr_locus), expr.get_locus ());
     286              : 
     287          572 :   infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ());
     288              : }
     289              : 
     290              : void
     291        13575 : TypeCheckExpr::visit (HIR::CallExpr &expr)
     292              : {
     293        13575 :   TyTy::BaseType *function_tyty = TypeCheckExpr::Resolve (expr.get_fnexpr ());
     294              : 
     295        13574 :   rust_debug_loc (expr.get_locus (), "resolved_call_expr to: {%s}",
     296              :                   function_tyty->get_name ().c_str ());
     297              : 
     298        13574 :   TyTy::VariantDef &variant = TyTy::VariantDef::get_error_node ();
     299        13574 :   if (function_tyty->get_kind () == TyTy::TypeKind::ADT)
     300              :     {
     301         1900 :       TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (function_tyty);
     302         1900 :       if (adt->is_enum ())
     303              :         {
     304              :           // lookup variant id
     305          967 :           HirId variant_id;
     306          967 :           bool ok = context->lookup_variant_definition (
     307          967 :             expr.get_fnexpr ().get_mappings ().get_hirid (), &variant_id);
     308              : 
     309          967 :           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          966 :           TyTy::VariantDef *lookup_variant = nullptr;
     318          966 :           ok = adt->lookup_variant_by_id (variant_id, &lookup_variant);
     319          966 :           rust_assert (ok);
     320              : 
     321          966 :           variant = std::move (*lookup_variant->clone ());
     322              :         }
     323              :       else
     324              :         {
     325          933 :           rust_assert (adt->number_of_variants () == 1);
     326          933 :           variant = std::move (*adt->get_variants ().at (0)->clone ());
     327              :         }
     328         1899 :       infered
     329         1899 :         = TyTy::TypeCheckCallExpr::go (function_tyty, expr, variant, context);
     330         1899 :       return;
     331              :     }
     332              : 
     333        11674 :   bool resolved_fn_trait_call
     334        11674 :     = resolve_fn_trait_call (expr, function_tyty, &infered);
     335        11674 :   if (resolved_fn_trait_call)
     336              :     return;
     337              : 
     338        11608 :   bool valid_tyty
     339        11648 :     = function_tyty->is<TyTy::FnType> () || function_tyty->is<TyTy::FnPtr> ();
     340           11 :   if (!valid_tyty)
     341              :     {
     342           11 :       bool emit_error = !function_tyty->is<TyTy::ErrorType> ();
     343           11 :       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        11597 :   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        11597 :   auto discriminant_type_lookup
     357        11597 :     = mappings.lookup_lang_item (LangItem::Kind::DISCRIMINANT_TYPE);
     358        11597 :   bool is_discriminant_type = false;
     359        11597 :   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        12421 :       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         2545 : TypeCheckExpr::visit (HIR::AssignmentExpr &expr)
     402              : {
     403         2545 :   infered = TyTy::TupleType::get_unit_type ();
     404              : 
     405         2545 :   auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
     406         2545 :   auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
     407              : 
     408         5090 :   coercion_site (expr.get_mappings ().get_hirid (),
     409         2545 :                  TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()),
     410         2545 :                  TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()),
     411              :                  expr.get_locus ());
     412         2545 : }
     413              : 
     414              : void
     415          705 : TypeCheckExpr::visit (HIR::CompoundAssignmentExpr &expr)
     416              : {
     417          705 :   infered = TyTy::TupleType::get_unit_type ();
     418              : 
     419          705 :   auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
     420          705 :   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         1410 :   coercion_site (expr.get_mappings ().get_hirid (),
     425          705 :                  TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()),
     426          705 :                  TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()),
     427              :                  expr.get_locus ());
     428              : 
     429          705 :   auto lang_item_type
     430          705 :     = LangItem::CompoundAssignmentOperatorToLangItem (expr.get_expr_type ());
     431          705 :   bool operator_overloaded
     432          705 :     = resolve_operator_overload (lang_item_type, expr, lhs, rhs);
     433          705 :   if (operator_overloaded)
     434              :     return;
     435              : 
     436          691 :   bool valid_lhs = validate_arithmetic_type (lhs, expr.get_expr_type ());
     437          691 :   bool valid_rhs = validate_arithmetic_type (rhs, expr.get_expr_type ());
     438          691 :   bool valid = valid_lhs && valid_rhs;
     439          691 :   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        21322 : TypeCheckExpr::visit (HIR::LiteralExpr &expr)
     451              : {
     452        21322 :   infered = resolve_literal (expr.get_mappings (), expr.get_literal (),
     453              :                              expr.get_locus ());
     454        21322 : }
     455              : 
     456              : void
     457         3719 : TypeCheckExpr::visit (HIR::ArithmeticOrLogicalExpr &expr)
     458              : {
     459         3719 :   auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
     460         3719 :   auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
     461              : 
     462         3719 :   auto lang_item_type = LangItem::OperatorToLangItem (expr.get_expr_type ());
     463         3719 :   bool operator_overloaded
     464         3719 :     = resolve_operator_overload (lang_item_type, expr, lhs, rhs);
     465         3719 :   if (operator_overloaded)
     466              :     return;
     467              : 
     468         3512 :   bool valid_lhs = validate_arithmetic_type (lhs, expr.get_expr_type ());
     469         3512 :   bool valid_rhs = validate_arithmetic_type (rhs, expr.get_expr_type ());
     470         3512 :   bool valid = valid_lhs && valid_rhs;
     471         3512 :   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         3509 :   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         3440 :     default:
     493         3440 :       {
     494         6880 :         infered = unify_site (
     495         3440 :           expr.get_mappings ().get_hirid (),
     496         3440 :           TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()),
     497         3440 :           TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()),
     498              :           expr.get_locus ());
     499              :       }
     500         3440 :       break;
     501              :     }
     502              : }
     503              : 
     504              : void
     505         3742 : TypeCheckExpr::visit (HIR::ComparisonExpr &expr)
     506              : {
     507         3742 :   auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
     508         3742 :   auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
     509              : 
     510         3742 :   auto borrowed_lhs
     511         3742 :     = new TyTy::ReferenceType (mappings.get_next_hir_id (),
     512         3742 :                                TyTy::TyVar (lhs->get_ref ()), Mutability::Imm);
     513         3742 :   context->insert_implicit_type (borrowed_lhs->get_ref (), borrowed_lhs);
     514              : 
     515         3742 :   auto borrowed_rhs
     516         3742 :     = new TyTy::ReferenceType (mappings.get_next_hir_id (),
     517         3742 :                                TyTy::TyVar (rhs->get_ref ()), Mutability::Imm);
     518         3742 :   context->insert_implicit_type (borrowed_rhs->get_ref (), borrowed_rhs);
     519              : 
     520         3742 :   auto seg_name = LangItem::ComparisonToSegment (expr.get_expr_type ());
     521         7484 :   auto segment = HIR::PathIdentSegment (seg_name);
     522         3742 :   auto lang_item_type = LangItem::ComparisonToLangItem (expr.get_expr_type ());
     523              : 
     524         3742 :   bool operator_overloaded
     525         3742 :     = resolve_operator_overload (lang_item_type, expr, lhs, borrowed_rhs,
     526              :                                  segment, true, nullptr, borrowed_lhs);
     527         3742 :   if (operator_overloaded)
     528          991 :     return;
     529              : 
     530         5502 :   unify_site (expr.get_mappings ().get_hirid (),
     531         2751 :               TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()),
     532         2751 :               TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()),
     533              :               expr.get_locus ());
     534              : 
     535         2751 :   bool ok = context->lookup_builtin ("bool", &infered);
     536         2751 :   rust_assert (ok);
     537         3742 : }
     538              : 
     539              : void
     540          425 : TypeCheckExpr::visit (HIR::LazyBooleanExpr &expr)
     541              : {
     542          425 :   auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
     543          425 :   auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
     544              : 
     545              :   // we expect the lhs and rhs must be bools at this point
     546          425 :   TyTy::BaseType *boolean_node = nullptr;
     547          425 :   bool ok = context->lookup_builtin ("bool", &boolean_node);
     548          425 :   rust_assert (ok);
     549              : 
     550              :   // verify the lhs and rhs before unifying together
     551          850 :   lhs = unify_site (expr.get_mappings ().get_hirid (),
     552              :                     TyTy::TyWithLocation (boolean_node,
     553          425 :                                           expr.get_lhs ().get_locus ()),
     554          425 :                     TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()),
     555              :                     expr.get_locus ());
     556              : 
     557          850 :   rhs = unify_site (expr.get_mappings ().get_hirid (),
     558              :                     TyTy::TyWithLocation (boolean_node,
     559          425 :                                           expr.get_rhs ().get_locus ()),
     560          425 :                     TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()),
     561              :                     expr.get_locus ());
     562              : 
     563          425 :   infered
     564          850 :     = unify_site (expr.get_mappings ().get_hirid (),
     565          425 :                   TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()),
     566          425 :                   TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()),
     567              :                   expr.get_locus ());
     568          425 : }
     569              : 
     570              : void
     571          707 : TypeCheckExpr::visit (HIR::NegationExpr &expr)
     572              : {
     573          707 :   auto negated_expr_ty = TypeCheckExpr::Resolve (expr.get_expr ());
     574              : 
     575              :   // check for operator overload
     576          707 :   auto lang_item_type
     577          707 :     = LangItem::NegationOperatorToLangItem (expr.get_expr_type ());
     578          707 :   bool operator_overloaded
     579          707 :     = resolve_operator_overload (lang_item_type, expr, negated_expr_ty,
     580              :                                  nullptr);
     581          707 :   if (operator_overloaded)
     582              :     return;
     583              : 
     584              :   // https://doc.rust-lang.org/reference/expressions/operator-expr.html#negation-operators
     585          693 :   switch (expr.get_expr_type ())
     586              :     {
     587          411 :     case NegationOperator::NEGATE:
     588          411 :       {
     589          411 :         bool valid
     590          411 :           = (negated_expr_ty->get_kind () == TyTy::TypeKind::INT)
     591          269 :             || (negated_expr_ty->get_kind () == TyTy::TypeKind::UINT)
     592          269 :             || (negated_expr_ty->get_kind () == TyTy::TypeKind::FLOAT)
     593          267 :             || (negated_expr_ty->get_kind () == TyTy::TypeKind::ISIZE)
     594          264 :             || (negated_expr_ty->get_kind () == TyTy::TypeKind::USIZE)
     595          264 :             || (negated_expr_ty->get_kind () == TyTy::TypeKind::INFER
     596          263 :                 && (((TyTy::InferType *) negated_expr_ty)->get_infer_kind ()
     597              :                     == TyTy::InferType::INTEGRAL))
     598          412 :             || (negated_expr_ty->get_kind () == TyTy::TypeKind::INFER
     599            0 :                 && (((TyTy::InferType *) negated_expr_ty)->get_infer_kind ()
     600          692 :                     == 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          692 :                     == 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          691 :   infered = negated_expr_ty->clone ();
     632          691 :   infered->append_reference (negated_expr_ty->get_ref ());
     633              : }
     634              : 
     635              : void
     636         1285 : TypeCheckExpr::visit (HIR::IfExpr &expr)
     637              : {
     638         1285 :   TyTy::BaseType *bool_ty = nullptr;
     639         1285 :   bool ok = context->lookup_builtin ("bool", &bool_ty);
     640         1285 :   rust_assert (ok);
     641              : 
     642         1285 :   TyTy::BaseType *cond_type = TypeCheckExpr::Resolve (expr.get_if_condition ());
     643              : 
     644         2570 :   unify_site (expr.get_mappings ().get_hirid (), TyTy::TyWithLocation (bool_ty),
     645              :               TyTy::TyWithLocation (cond_type,
     646         1285 :                                     expr.get_if_condition ().get_locus ()),
     647              :               expr.get_locus ());
     648              : 
     649         1285 :   TyTy::BaseType *block_type = TypeCheckExpr::Resolve (expr.get_if_block ());
     650              : 
     651         1285 :   TyTy::BaseType *unit_ty = nullptr;
     652         1285 :   ok = context->lookup_builtin ("()", &unit_ty);
     653         1285 :   rust_assert (ok);
     654              : 
     655         1285 :   infered
     656         2570 :     = coercion_site (expr.get_mappings ().get_hirid (),
     657         1285 :                      TyTy::TyWithLocation (unit_ty),
     658              :                      TyTy::TyWithLocation (block_type,
     659         1285 :                                            expr.get_if_block ().get_locus ()),
     660              :                      expr.get_locus ());
     661         1285 : }
     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         4000 : TypeCheckExpr::visit (HIR::UnsafeBlockExpr &expr)
     698              : {
     699         4000 :   infered = TypeCheckExpr::Resolve (expr.get_block_expr ());
     700         4000 : }
     701              : 
     702              : void
     703        25266 : TypeCheckExpr::visit (HIR::BlockExpr &expr)
     704              : {
     705        25266 :   bool has_label = expr.has_label ();
     706        25266 :   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        25266 :   TyTy::BaseType *outer_expected = context->peek_expected_type ();
     712        25266 :   context->push_expected_type (nullptr);
     713              : 
     714        50613 :   for (auto &s : expr.get_statements ())
     715              :     {
     716        25347 :       if (!s->is_item ())
     717        24893 :         continue;
     718              : 
     719          454 :       TypeCheckStmt::Resolve (*s);
     720              :     }
     721              : 
     722        50613 :   for (auto &s : expr.get_statements ())
     723              :     {
     724        25347 :       if (s->is_item ())
     725          454 :         continue;
     726              : 
     727        24893 :       auto resolved = TypeCheckStmt::Resolve (*s);
     728        24893 :       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        25266 :           return;
     735              :         }
     736              : 
     737        24893 :       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        25266 :   context->pop_expected_type ();
     747              : 
     748        25266 :   TyTy::BaseType *tail_expr_type = nullptr;
     749        25266 :   if (expr.has_expr ())
     750              :     {
     751        18120 :       context->push_expected_type (outer_expected);
     752        18120 :       tail_expr_type = TypeCheckExpr::Resolve (expr.get_final_expr ());
     753        18120 :       context->pop_expected_type ();
     754              :     }
     755              : 
     756        25266 :   TyTy::BaseType *label_context_type = nullptr;
     757        25266 :   bool label_context_type_infered = false;
     758        25266 :   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        25266 :   if (tail_expr_type != nullptr)
     770              :     {
     771        18120 :       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        18118 :         infered = tail_expr_type;
     785              :     }
     786         7146 :   else if (label_context_type_infered)
     787            1 :     infered = label_context_type;
     788         7145 :   else if (expr.is_tail_reachable ())
     789         6654 :     infered = TyTy::TupleType::get_unit_type ();
     790              :   else
     791              :     {
     792              :       // FIXME this seems wrong
     793          491 :       infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ());
     794              :     }
     795              : }
     796              : 
     797              : void
     798          811 : TypeCheckExpr::visit (HIR::AnonConst &expr)
     799              : {
     800          811 :   if (!expr.is_deferred ())
     801              :     {
     802          799 :       infered = TypeCheckExpr::Resolve (expr.get_inner_expr ());
     803          799 :       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          451 : TypeCheckExpr::visit (HIR::ArrayExpr &expr)
    1146              : {
    1147          451 :   auto &elements = expr.get_internal_elements ();
    1148              : 
    1149          451 :   TyTy::BaseType *expected_ty = nullptr;
    1150          451 :   bool ok = context->lookup_builtin ("usize", &expected_ty);
    1151          451 :   rust_assert (ok);
    1152              : 
    1153          451 :   HIR::Expr *capacity_expr = nullptr;
    1154          451 :   TyTy::BaseType *element_type = nullptr;
    1155          451 :   TyTy::BaseType *capacity_type = nullptr;
    1156              : 
    1157          451 :   switch (elements.get_array_expr_type ())
    1158              :     {
    1159          134 :     case HIR::ArrayElems::ArrayExprType::COPIED:
    1160          134 :       {
    1161          134 :         HIR::ArrayElemsCopied &elems
    1162              :           = static_cast<HIR::ArrayElemsCopied &> (elements);
    1163          134 :         context->push_const_context ();
    1164          134 :         element_type = TypeCheckExpr::Resolve (elems.get_elem_to_copy ());
    1165          134 :         context->pop_const_context ();
    1166              : 
    1167          134 :         auto capacity_expr_ty
    1168          134 :           = TypeCheckExpr::Resolve (elems.get_num_copies_expr ());
    1169          134 :         if (capacity_expr_ty->is<TyTy::ErrorType> ())
    1170           10 :           return;
    1171              : 
    1172          128 :         context->insert_type (elems.get_num_copies_expr ().get_mappings (),
    1173              :                               expected_ty);
    1174              : 
    1175          256 :         auto result = unify_site (
    1176          128 :           expr.get_mappings ().get_hirid (), TyTy::TyWithLocation (expected_ty),
    1177              :           TyTy::TyWithLocation (capacity_expr_ty,
    1178          128 :                                 elems.get_num_copies_expr ().get_locus ()),
    1179              :           expr.get_locus ());
    1180          128 :         if (result->is<TyTy::ErrorType> ())
    1181              :           return;
    1182              : 
    1183          124 :         capacity_expr = &elems.get_num_copies_expr ();
    1184          124 :         capacity_type = expected_ty;
    1185              :       }
    1186          124 :       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.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          441 :   rust_assert (capacity_expr);
    1231          441 :   rust_assert (capacity_type);
    1232          441 :   auto ctx = Compile::Context::get ();
    1233          441 :   tree capacity_value
    1234          441 :     = 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          441 :   HirId capacity_expr_id = capacity_expr->get_mappings ().get_hirid ();
    1240          441 :   auto const_type
    1241              :     = new TyTy::ConstValueType (capacity_value, expected_ty, capacity_expr_id,
    1242          441 :                                 capacity_expr_id);
    1243              : 
    1244              :   // Insert the ConstValueType at its ref
    1245          441 :   context->insert_type (capacity_expr->get_mappings (),
    1246          441 :                         const_type->as_base_type ());
    1247              : 
    1248          441 :   infered
    1249          882 :     = new TyTy::ArrayType (expr.get_mappings ().get_hirid (), expr.get_locus (),
    1250              :                            TyTy::TyVar (
    1251          441 :                              const_type->as_base_type ()->get_ty_ref ()),
    1252          882 :                            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         1444 : TypeCheckExpr::visit (HIR::StructExprStructFields &struct_expr)
    1316              : {
    1317         1444 :   infered = TypeCheckStructExpr::Resolve (struct_expr);
    1318         1444 : }
    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         5120 : TypeCheckExpr::visit (HIR::FieldAccessExpr &expr)
    1328              : {
    1329         5120 :   auto struct_base = TypeCheckExpr::Resolve (expr.get_receiver_expr ());
    1330              : 
    1331              :   // Box<T> autoderef
    1332         5120 :   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         5120 :   if (struct_base->get_kind () == TyTy::TypeKind::REF)
    1339              :     {
    1340         3504 :       TyTy::ReferenceType *r = static_cast<TyTy::ReferenceType *> (struct_base);
    1341         3504 :       struct_base = r->get_base ();
    1342              :     }
    1343              : 
    1344         5120 :   bool is_valid_type = struct_base->get_kind () == TyTy::TypeKind::ADT;
    1345         5120 :   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         5118 :   TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (struct_base);
    1353         5118 :   rust_assert (adt->number_of_variants () > 0);
    1354         5118 :   TyTy::VariantDef *vaiant = adt->get_variants ().at (0);
    1355              : 
    1356         5118 :   TyTy::StructFieldType *lookup = nullptr;
    1357         5118 :   bool found = vaiant->lookup_field (expr.get_field_name ().as_string (),
    1358              :                                      &lookup, nullptr);
    1359         5118 :   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         5114 :   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         3154 : TypeCheckExpr::visit (HIR::MethodCallExpr &expr)
    1462              : {
    1463         3154 :   auto receiver_tyty = TypeCheckExpr::Resolve (expr.get_receiver ());
    1464         3154 :   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         3153 :   rust_debug_loc (expr.get_locus (), "attempting to resolve method for %s",
    1472              :                   receiver_tyty->debug_str ().c_str ());
    1473         3153 :   auto candidates
    1474              :     = MethodResolver::Probe (receiver_tyty,
    1475         3153 :                              expr.get_method_name ().get_segment ());
    1476         3153 :   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         3146 :   tl::optional<const MethodCandidate &> candidate = *candidates.begin ();
    1488              : 
    1489         3146 :   if (candidates.size () > 1)
    1490           16 :     candidate = handle_multiple_candidates (expr, candidates);
    1491              : 
    1492         3146 :   if (!candidate)
    1493              :     return;
    1494              : 
    1495         3144 :   auto found_candidate = *candidate;
    1496              : 
    1497         3144 :   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         3144 :   Adjuster adj (receiver_tyty);
    1505         3144 :   TyTy::BaseType *adjusted_self = adj.adjust_type (found_candidate.adjustments);
    1506         3144 :   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         3144 :   HirId autoderef_mappings_id
    1514         3144 :     = expr.get_receiver ().get_mappings ().get_hirid ();
    1515         3144 :   context->insert_autoderef_mappings (autoderef_mappings_id,
    1516              :                                       std::move (found_candidate.adjustments));
    1517              : 
    1518         3144 :   PathProbeCandidate &resolved_candidate = found_candidate.candidate;
    1519         3144 :   TyTy::BaseType *lookup_tyty = found_candidate.candidate.ty;
    1520         3144 :   NodeId resolved_node_id
    1521         3144 :     = resolved_candidate.is_impl_candidate ()
    1522         3144 :         ? resolved_candidate.item.impl.impl_item->get_impl_mappings ()
    1523         2155 :             .get_nodeid ()
    1524          989 :         : resolved_candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
    1525              : 
    1526         3144 :   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         3144 :   TyTy::BaseType *lookup = lookup_tyty;
    1535         3144 :   TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
    1536         6288 :   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         3144 :   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         3144 :   if (resolved_candidate.is_impl_candidate ())
    1549              :     {
    1550         2155 :       auto infer_arguments = TyTy::SubstitutionArgumentMappings::empty ();
    1551         2155 :       infer_arguments.get_mut_regions ()
    1552         2155 :         = fn->get_used_arguments ().get_regions ();
    1553         2155 :       HIR::ImplBlock &impl = *resolved_candidate.item.impl.parent;
    1554         2155 :       TyTy::BaseType *impl_self_infer
    1555         2155 :         = TypeCheckItem::ResolveImplBlockSelfWithInference (impl,
    1556              :                                                             expr.get_locus (),
    1557              :                                                             &infer_arguments);
    1558         2155 :       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         2155 :       if (!infer_arguments.is_empty ())
    1568          587 :         lookup = SubstMapperInternal::Resolve (lookup, infer_arguments);
    1569         2155 :     }
    1570              : 
    1571              :   // apply any remaining generic arguments
    1572         3144 :   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         3115 :   else if (lookup->needs_generic_substitutions ())
    1586              :     {
    1587          892 :       rust_debug ("method needs inference: {%s}",
    1588              :                   lookup->debug_str ().c_str ());
    1589          892 :       lookup = SubstMapper::InferSubst (lookup,
    1590          892 :                                         expr.get_method_name ().get_locus ());
    1591              :     }
    1592              : 
    1593         3143 :   rust_debug ("type-checking method_call: {%s}", lookup->debug_str ().c_str ());
    1594              : 
    1595         3143 :   TyTy::BaseType *function_ret_tyty
    1596         3143 :     = TyTy::TypeCheckMethodCallExpr::go (static_cast<TyTy::FnType *> (lookup),
    1597              :                                          expr, adjusted_self, context);
    1598         3143 :   if (function_ret_tyty == nullptr
    1599         3143 :       || 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         3143 :   context->insert_type (expr.get_method_name ().get_mappings (), lookup);
    1608              : 
    1609         3143 :   auto &nr_ctx = Resolver2_0::FinalizedNameResolutionContext::get ();
    1610              : 
    1611         3143 :   nr_ctx.map_usage (Resolver2_0::Usage (expr.get_mappings ().get_nodeid ()),
    1612         3143 :                     Resolver2_0::Definition (resolved_node_id),
    1613              :                     Resolver2_0::Namespace::Values);
    1614              : 
    1615              :   // return the result of the function back
    1616         3143 :   infered = function_ret_tyty;
    1617         3154 : }
    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         2152 : TypeCheckExpr::visit (HIR::BorrowExpr &expr)
    1722              : {
    1723         2152 :   TyTy::BaseType *resolved_base = TypeCheckExpr::Resolve (expr.get_expr ());
    1724         2152 :   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         2151 :   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         2142 :   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         2138 :   infered = new TyTy::ReferenceType (expr.get_mappings ().get_hirid (),
    1757         2138 :                                      TyTy::TyVar (resolved_base->get_ref ()),
    1758         4276 :                                      expr.get_mut ());
    1759              : }
    1760              : 
    1761              : void
    1762         4282 : TypeCheckExpr::visit (HIR::DereferenceExpr &expr)
    1763              : {
    1764         4282 :   TyTy::BaseType *resolved_base = TypeCheckExpr::Resolve (expr.get_expr ());
    1765              : 
    1766         4282 :   rust_debug_loc (expr.get_locus (), "attempting deref operator overload");
    1767         4282 :   auto lang_item_type = LangItem::Kind::DEREF;
    1768         4282 :   bool operator_overloaded
    1769         4282 :     = resolve_operator_overload (lang_item_type, expr, resolved_base, nullptr);
    1770         4282 :   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         4282 :   bool is_valid_type = resolved_base->get_kind () == TyTy::TypeKind::REF
    1779         4282 :                        || resolved_base->get_kind () == TyTy::TypeKind::POINTER;
    1780              : 
    1781         4282 :   auto try_owned_box = TyTy::try_get_box_inner_type (resolved_base);
    1782              : 
    1783         4282 :   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         4282 :   if (try_owned_box)
    1791              :     {
    1792            1 :       infered = (*try_owned_box)->clone ();
    1793              :     }
    1794         4281 :   else if (resolved_base->get_kind () == TyTy::TypeKind::REF)
    1795              :     {
    1796         4072 :       TyTy::ReferenceType *ref_base
    1797              :         = static_cast<TyTy::ReferenceType *> (resolved_base);
    1798         4072 :       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         5688 : TypeCheckExpr::visit (HIR::TypeCastExpr &expr)
    1810              : {
    1811         5688 :   TyTy::BaseType *expr_to_convert
    1812         5688 :     = TypeCheckExpr::Resolve (expr.get_casted_expr ());
    1813         5688 :   TyTy::BaseType *tyty_to_convert_to
    1814         5688 :     = TypeCheckType::Resolve (expr.get_type_to_convert_to ());
    1815              : 
    1816         5688 :   TyTy::TyWithLocation from (expr_to_convert,
    1817         5688 :                              expr.get_casted_expr ().get_locus ());
    1818         5688 :   TyTy::TyWithLocation to (tyty_to_convert_to,
    1819         5688 :                            expr.get_type_to_convert_to ().get_locus ());
    1820         5688 :   infered = cast_site (expr.get_mappings ().get_hirid (), from, to,
    1821              :                        expr.get_locus ());
    1822         5688 : }
    1823              : 
    1824              : void
    1825         1142 : 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         1142 :   TyTy::BaseType *scrutinee_tyty
    1830         1142 :     = 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         1142 :   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         1137 :   bool saw_error = false;
    1845         1137 :   std::vector<TyTy::BaseType *> kase_block_tys;
    1846         3763 :   for (auto &kase : expr.get_match_cases ())
    1847              :     {
    1848              :       // lets check the arms
    1849         2626 :       HIR::MatchArm &kase_arm = kase.get_arm ();
    1850         2626 :       auto &pattern = kase_arm.get_pattern ();
    1851         2626 :       TyTy::BaseType *kase_arm_ty
    1852         2626 :         = TypeCheckPattern::Resolve (*pattern, scrutinee_tyty);
    1853         2626 :       if (kase_arm_ty->get_kind () == TyTy ::TypeKind::ERROR)
    1854              :         {
    1855           11 :           saw_error = true;
    1856           11 :           continue;
    1857              :         }
    1858              : 
    1859         5230 :       TyTy::BaseType *checked_kase = unify_site (
    1860         2615 :         expr.get_mappings ().get_hirid (),
    1861              :         TyTy::TyWithLocation (scrutinee_tyty,
    1862         2615 :                               expr.get_scrutinee_expr ().get_locus ()),
    1863         2615 :         TyTy::TyWithLocation (kase_arm_ty, pattern->get_locus ()),
    1864              :         expr.get_locus ());
    1865         2615 :       if (checked_kase->get_kind () == TyTy::TypeKind::ERROR)
    1866              :         {
    1867            0 :           saw_error = true;
    1868            0 :           continue;
    1869              :         }
    1870              : 
    1871              :       // check the kase type
    1872         2615 :       TyTy::BaseType *kase_block_ty = TypeCheckExpr::Resolve (kase.get_expr ());
    1873         2615 :       kase_block_tys.push_back (kase_block_ty);
    1874              :     }
    1875         1137 :   if (saw_error)
    1876              :     return;
    1877              : 
    1878         1131 :   if (kase_block_tys.size () == 0)
    1879              :     {
    1880            0 :       infered = TyTy::TupleType::get_unit_type ();
    1881            0 :       return;
    1882              :     }
    1883              : 
    1884              :   // this is a LUB
    1885         1131 :   infered = kase_block_tys.at (0);
    1886         2607 :   for (size_t i = 1; i < kase_block_tys.size (); i++)
    1887              :     {
    1888         1476 :       TyTy::BaseType *kase_ty = kase_block_tys.at (i);
    1889         1476 :       infered
    1890         1476 :         = coercion_site (expr.get_mappings ().get_hirid (),
    1891         1476 :                          TyTy::TyWithLocation (infered),
    1892         1476 :                          TyTy::TyWithLocation (kase_ty), expr.get_locus ());
    1893              :     }
    1894         1137 : }
    1895              : 
    1896              : void
    1897           66 : TypeCheckExpr::visit (HIR::ClosureExpr &expr)
    1898              : {
    1899           66 :   std::vector<TyTy::SubstitutionParamMapping> subst_refs;
    1900           66 :   HirId ref = expr.get_mappings ().get_hirid ();
    1901           66 :   DefId id = expr.get_mappings ().get_defid ();
    1902           66 :   RustIdent ident{CanonicalPath::create_empty (), expr.get_locus ()};
    1903              : 
    1904           66 :   if (context->have_function_context ())
    1905              :     {
    1906           64 :       TypeCheckContextItem current_context = context->peek_context ();
    1907           64 :       TyTy::FnType *current_context_fndecl
    1908           64 :         = current_context.get_context_type ();
    1909              : 
    1910           64 :       ident = RustIdent{current_context_fndecl->get_ident ().path,
    1911           64 :                         expr.get_locus ()};
    1912              : 
    1913           64 :       subst_refs = current_context_fndecl->clone_substs ();
    1914              :     }
    1915              : 
    1916           66 :   std::vector<TyTy::TyVar> parameter_types;
    1917          126 :   for (auto &p : expr.get_params ())
    1918              :     {
    1919           60 :       TyTy::BaseType *param_tyty = nullptr;
    1920           60 :       if (p.has_type_given ())
    1921              :         {
    1922           58 :           param_tyty = TypeCheckType::Resolve (p.get_type ());
    1923              :         }
    1924              :       else
    1925              :         {
    1926            2 :           param_tyty = ClosureParamInfer::Resolve (p.get_pattern ());
    1927              :         }
    1928              : 
    1929           60 :       TyTy::TyVar param_ty (param_tyty->get_ref ());
    1930           60 :       parameter_types.push_back (param_ty);
    1931              : 
    1932           60 :       TypeCheckPattern::Resolve (p.get_pattern (), param_ty.get_tyty ());
    1933              :     }
    1934              : 
    1935              :   // we generate an implicit hirid for the closure args
    1936           66 :   HirId implicit_args_id = mappings.get_next_hir_id ();
    1937           66 :   TyTy::TupleType *closure_args
    1938              :     = new TyTy::TupleType (implicit_args_id, expr.get_locus (),
    1939           66 :                            parameter_types);
    1940           66 :   context->insert_implicit_type (closure_args->get_ref (), closure_args);
    1941              : 
    1942           66 :   location_t result_type_locus = expr.has_return_type ()
    1943           66 :                                    ? expr.get_return_type ().get_locus ()
    1944           66 :                                    : expr.get_locus ();
    1945           66 :   TyTy::TyVar result_type
    1946           66 :     = expr.has_return_type ()
    1947           66 :         ? TyTy::TyVar (
    1948              :           TypeCheckType::Resolve (expr.get_return_type ())->get_ref ())
    1949           66 :         : TyTy::TyVar::get_implicit_infer_var (expr.get_locus ());
    1950              : 
    1951              :   // resolve the block
    1952           66 :   location_t closure_expr_locus = expr.get_expr ().get_locus ();
    1953           66 :   TyTy::BaseType *closure_expr_ty = TypeCheckExpr::Resolve (expr.get_expr ());
    1954          132 :   coercion_site (expr.get_mappings ().get_hirid (),
    1955              :                  TyTy::TyWithLocation (result_type.get_tyty (),
    1956           66 :                                        result_type_locus),
    1957           66 :                  TyTy::TyWithLocation (closure_expr_ty, closure_expr_locus),
    1958              :                  expr.get_locus ());
    1959              : 
    1960              :   // generate the closure type
    1961           66 :   NodeId closure_node_id = expr.get_mappings ().get_nodeid ();
    1962              : 
    1963              :   // Resolve closure captures
    1964              : 
    1965           66 :   std::set<NodeId> captures;
    1966              : 
    1967           66 :   if (auto opt_cap
    1968           66 :       = Analysis::Mappings::get ().lookup_captures (closure_node_id))
    1969           42 :     for (auto cap : opt_cap.value ())
    1970           21 :       captures.insert (cap);
    1971              : 
    1972           66 :   infered = new TyTy::ClosureType (ref, id, ident, closure_args, result_type,
    1973          132 :                                    subst_refs, captures);
    1974              : 
    1975              :   // FIXME
    1976              :   // all closures automatically inherit the appropriate fn trait. Lets just
    1977              :   // assume FnOnce for now. I think this is based on the return type of the
    1978              :   // closure
    1979              : 
    1980           66 :   LangItem::Kind lang_item_type = LangItem::Kind::FN_ONCE;
    1981              : 
    1982           66 :   DefId respective_lang_item_id
    1983           66 :     = mappings.get_lang_item (lang_item_type, expr.get_locus ());
    1984              : 
    1985              :   // these lang items are always traits
    1986           65 :   HIR::Item *item = mappings.lookup_defid (respective_lang_item_id).value ();
    1987           65 :   rust_assert (item->get_item_kind () == HIR::Item::ItemKind::Trait);
    1988           65 :   HIR::Trait *trait_item = static_cast<HIR::Trait *> (item);
    1989              : 
    1990           65 :   TraitReference *trait = TraitResolver::Resolve (*trait_item);
    1991           65 :   rust_assert (!trait->is_error ());
    1992              : 
    1993           65 :   TyTy::TypeBoundPredicate predicate (*trait, BoundPolarity::RegularBound,
    1994           65 :                                       expr.get_locus ());
    1995              : 
    1996              :   // resolve the trait bound where the <(Args)> are the parameter tuple type
    1997           65 :   HIR::GenericArgs args = HIR::GenericArgs::create_empty (expr.get_locus ());
    1998              : 
    1999              :   // lets generate an implicit Type so that it resolves to the implict tuple
    2000              :   // type we have created
    2001           65 :   auto crate_num = mappings.get_current_crate ();
    2002           65 :   Analysis::NodeMapping mapping (crate_num, expr.get_mappings ().get_nodeid (),
    2003           65 :                                  implicit_args_id, UNKNOWN_LOCAL_DEFID);
    2004           65 :   HIR::TupleType *implicit_tuple
    2005              :     = new HIR::TupleType (mapping,
    2006              :                           {} // we dont need to fill this out because it will
    2007              :                              // auto resolve because the hir id's match
    2008              :                           ,
    2009           65 :                           expr.get_locus ());
    2010           65 :   args.get_type_args ().emplace_back (implicit_tuple);
    2011              : 
    2012              :   // apply the arguments
    2013           65 :   predicate.apply_generic_arguments (&args, false, false);
    2014              : 
    2015              :   // finally inherit the trait bound
    2016           65 :   infered->inherit_bound (predicate);
    2017           65 : }
    2018              : 
    2019              : bool
    2020        13238 : TypeCheckExpr::resolve_operator_overload (
    2021              :   LangItem::Kind lang_item_type, HIR::OperatorExprMeta expr,
    2022              :   TyTy::BaseType *lhs, TyTy::BaseType *rhs,
    2023              :   HIR::PathIdentSegment specified_segment, bool allow_defer,
    2024              :   TyTy::BaseType *result_type, TyTy::BaseType *probe_lhs)
    2025              : {
    2026              :   // look up lang item for arithmetic type
    2027        13238 :   std::string associated_item_name = LangItem::ToString (lang_item_type);
    2028              : 
    2029        13238 :   auto lang_item_defined = mappings.lookup_lang_item (lang_item_type);
    2030              :   // probe for the lang-item
    2031        13238 :   if (!lang_item_defined)
    2032              :     return false;
    2033              : 
    2034         3077 :   DefId &respective_lang_item_id = lang_item_defined.value ();
    2035         3077 :   auto def_lookup = mappings.lookup_defid (respective_lang_item_id);
    2036         3077 :   rust_assert (def_lookup.has_value ());
    2037              : 
    2038         3077 :   HIR::Item *def_item = def_lookup.value ();
    2039         3077 :   rust_assert (def_item->get_item_kind () == HIR::Item::ItemKind::Trait);
    2040         3077 :   HIR::Trait &trait = *static_cast<HIR::Trait *> (def_item);
    2041              : 
    2042              :   // we might be in a static or const context and unknown is fine
    2043         3077 :   TypeCheckContextItem current_context = TypeCheckContextItem::get_error ();
    2044         3077 :   if (context->have_function_context ())
    2045              :     {
    2046         3062 :       current_context = context->peek_context ();
    2047              :     }
    2048              : 
    2049         3077 :   auto segment = specified_segment.is_error ()
    2050         4332 :                    ? HIR::PathIdentSegment (associated_item_name)
    2051         3077 :                    : specified_segment;
    2052         3077 :   TyTy::BaseType *method_receiver = probe_lhs == nullptr ? lhs : probe_lhs;
    2053         3077 :   auto candidates
    2054         3077 :     = MethodResolver::Probe (method_receiver, segment, false, &trait);
    2055              : 
    2056              :   // remove any recursive candidates
    2057         3077 :   std::set<MethodCandidate> resolved_candidates;
    2058         6410 :   for (auto &c : candidates)
    2059              :     {
    2060         3333 :       const TyTy::BaseType *candidate_type = c.candidate.ty;
    2061         3333 :       rust_assert (candidate_type->get_kind () == TyTy::TypeKind::FNDEF);
    2062              : 
    2063         3333 :       const TyTy::FnType &fn
    2064              :         = *static_cast<const TyTy::FnType *> (candidate_type);
    2065              : 
    2066         3355 :       if (probe_lhs != nullptr
    2067         5180 :           && !types_compatable (TyTy::TyWithLocation (fn.get_self_type ()),
    2068         1847 :                                 TyTy::TyWithLocation (probe_lhs),
    2069              :                                 UNDEF_LOCATION, false /* emit_errors */))
    2070           22 :         continue;
    2071              : 
    2072         3311 :       DefId current_fn_defid = current_context.get_defid ();
    2073         6622 :       bool recursive_candidated = fn.get_id () == current_fn_defid;
    2074         1843 :       if (!recursive_candidated)
    2075              :         {
    2076         1843 :           resolved_candidates.insert (c);
    2077              :         }
    2078              :     }
    2079              : 
    2080         3077 :   std::vector<TyTy::BaseType *> select_args = {};
    2081         3077 :   if (rhs != nullptr)
    2082         2847 :     select_args = {rhs};
    2083         3077 :   auto selected_candidates
    2084         3077 :     = MethodResolver::Select (resolved_candidates, method_receiver, select_args,
    2085         3077 :                               result_type);
    2086              : 
    2087         3077 :   bool have_implementation_for_lang_item = selected_candidates.size () > 0;
    2088         3077 :   if (!have_implementation_for_lang_item)
    2089              :     return false;
    2090              : 
    2091         1507 :   if (selected_candidates.size () > 1)
    2092              :     {
    2093           15 :       if (!allow_defer)
    2094              :         return false;
    2095              : 
    2096           15 :       TyTy::TyVar result_type
    2097           15 :         = TyTy::TyVar::get_implicit_infer_var (expr.get_locus ());
    2098           15 :       TyTy::BaseType *result_tyty = result_type.get_tyty ();
    2099           15 :       rust_assert (result_tyty != nullptr);
    2100           15 :       rust_debug ("deferring operator expr=%u result-ref=%u result-ty-ref=%u "
    2101              :                   "lhs-ref=%u rhs-ref=%u",
    2102              :                   expr.get_mappings ().get_hirid (), result_type.get_ref (),
    2103              :                   result_tyty->get_ty_ref (), lhs->get_ref (),
    2104              :                   rhs == nullptr ? UNKNOWN_HIRID : rhs->get_ref ());
    2105           30 :       DeferredOpOverload defer (expr.get_mappings ().get_hirid (),
    2106              :                                 lang_item_type, specified_segment, expr,
    2107           30 :                                 result_type);
    2108           15 :       context->insert_deferred_operator_overload (std::move (defer));
    2109              : 
    2110           15 :       infered = result_tyty;
    2111           15 :       return true;
    2112           15 :     }
    2113              : 
    2114              :   // Get the adjusted self
    2115         1492 :   MethodCandidate candidate = *selected_candidates.begin ();
    2116         1492 :   if (probe_lhs != nullptr)
    2117          992 :     candidate.adjustments.insert (
    2118          992 :       candidate.adjustments.begin (),
    2119          992 :       Adjustment (Adjustment::AdjustmentType::IMM_REF, lhs, probe_lhs));
    2120         1492 :   Adjuster adj (lhs);
    2121         1492 :   TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments);
    2122              : 
    2123              :   // store the adjustments for code-generation to know what to do
    2124         1492 :   context->insert_autoderef_mappings (expr.get_lvalue_mappings ().get_hirid (),
    2125              :                                       std::move (candidate.adjustments));
    2126              : 
    2127         1492 :   PathProbeCandidate &resolved_candidate = candidate.candidate;
    2128         1492 :   TyTy::BaseType *lookup_tyty = candidate.candidate.ty;
    2129         1492 :   NodeId resolved_node_id
    2130         1492 :     = resolved_candidate.is_impl_candidate ()
    2131         1492 :         ? resolved_candidate.item.impl.impl_item->get_impl_mappings ()
    2132         1088 :             .get_nodeid ()
    2133          404 :         : resolved_candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
    2134              : 
    2135         1492 :   rust_assert (lookup_tyty->get_kind () == TyTy::TypeKind::FNDEF);
    2136         1492 :   TyTy::BaseType *lookup = lookup_tyty;
    2137         1492 :   TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
    2138         2984 :   rust_assert (fn->is_method ());
    2139              : 
    2140         1492 :   rust_debug ("is_impl_item_candidate: %s",
    2141              :               resolved_candidate.is_impl_candidate () ? "true" : "false");
    2142              : 
    2143              :   // in the case where we resolve to a trait bound we have to be careful we are
    2144              :   // able to do so there is a case where we are currently resolving the deref
    2145              :   // operator overload function which is generic and this might resolve to the
    2146              :   // trait item of deref which is not valid as its just another recursive case
    2147         1492 :   if (current_context.get_type () == TypeCheckContextItem::ItemType::IMPL_ITEM)
    2148              :     {
    2149          781 :       auto &impl_item = current_context.get_impl_item ();
    2150          781 :       HIR::ImplBlock *parent = impl_item.first;
    2151          781 :       HIR::Function *fn = impl_item.second;
    2152              : 
    2153          781 :       bool is_deref = lang_item_type == LangItem::Kind::DEREF
    2154          781 :                       || lang_item_type == LangItem::Kind::DEREF_MUT;
    2155         3124 :       bool is_deref_match = fn->get_function_name ().as_string ().compare (
    2156         1562 :                               LangItem::ToString (LangItem::Kind::DEREF))
    2157              :                               == 0
    2158         2196 :                             || fn->get_function_name ().as_string ().compare (
    2159         1415 :                                  LangItem::ToString (LangItem::Kind::DEREF_MUT))
    2160              :                                  == 0;
    2161              : 
    2162          781 :       bool is_recursive_op
    2163         1562 :         = fn->get_function_name ().as_string ().compare (associated_item_name)
    2164              :             == 0
    2165          781 :           || (is_deref && is_deref_match);
    2166          781 :       if (parent->has_trait_ref () && is_recursive_op)
    2167              :         {
    2168          336 :           TraitReference *trait_reference
    2169          336 :             = TraitResolver::Lookup (parent->get_trait_ref ());
    2170          336 :           if (!trait_reference->is_error ())
    2171              :             {
    2172          336 :               TyTy::BaseType *lookup = nullptr;
    2173          336 :               bool ok = context->lookup_type (fn->get_mappings ().get_hirid (),
    2174              :                                               &lookup);
    2175          336 :               rust_assert (ok);
    2176          336 :               rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
    2177              : 
    2178          336 :               TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup);
    2179          672 :               rust_assert (fntype->is_method ());
    2180              : 
    2181          336 :               bool is_lang_item_impl
    2182          336 :                 = trait_reference->get_mappings ().get_defid ()
    2183          338 :                     == respective_lang_item_id
    2184            2 :                   || (is_deref && is_deref_match);
    2185          336 :               bool self_is_lang_item_self
    2186          336 :                 = fntype->get_self_type ()->is_equal (*adjusted_self);
    2187          336 :               bool recursive_operator_overload
    2188              :                 = is_lang_item_impl && self_is_lang_item_self;
    2189              : 
    2190          336 :               if (recursive_operator_overload)
    2191          150 :                 return false;
    2192              :             }
    2193              :         }
    2194              :     }
    2195              : 
    2196              :   // we found a valid operator overload
    2197         1342 :   rust_debug_loc (expr.get_locus (), "resolved operator overload to: {%u} {%s}",
    2198              :                   candidate.candidate.ty->get_ref (),
    2199              :                   candidate.candidate.ty->debug_str ().c_str ());
    2200              : 
    2201              :   // handle generics
    2202         1342 :   if (lookup->needs_generic_substitutions ())
    2203          397 :     lookup = SubstMapper::InferSubst (lookup, expr.get_locus ());
    2204              : 
    2205              :   // type check the arguments if required
    2206         1342 :   TyTy::FnType *type = static_cast<TyTy::FnType *> (lookup);
    2207         1342 :   rust_assert (type->num_params () > 0);
    2208         1342 :   auto &fnparam = type->param_at (0);
    2209              : 
    2210              :   // typecheck the self
    2211         2684 :   unify_site (expr.get_mappings ().get_hirid (),
    2212         1342 :               TyTy::TyWithLocation (fnparam.get_type ()),
    2213         1342 :               TyTy::TyWithLocation (adjusted_self), expr.get_locus ());
    2214         1342 :   if (rhs == nullptr)
    2215              :     {
    2216           64 :       rust_assert (type->num_params () == 1);
    2217              :     }
    2218              :   else
    2219              :     {
    2220         1278 :       rust_assert (type->num_params () == 2);
    2221         1278 :       auto &fnparam = type->param_at (1);
    2222         2556 :       unify_site (expr.get_mappings ().get_hirid (),
    2223         1278 :                   TyTy::TyWithLocation (fnparam.get_type ()),
    2224         1278 :                   TyTy::TyWithLocation (rhs), expr.get_locus ());
    2225              :     }
    2226              : 
    2227         1342 :   rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
    2228         1342 :   fn = static_cast<TyTy::FnType *> (lookup);
    2229         1342 :   fn->monomorphize ();
    2230              : 
    2231              :   // get the return type
    2232         1342 :   TyTy::BaseType *function_ret_tyty
    2233         1342 :     = type->get_return_type ()->monomorphized_clone ();
    2234              : 
    2235              :   // store the expected fntype
    2236         1342 :   context->insert_operator_overload (expr.get_mappings ().get_hirid (), type);
    2237              : 
    2238              :   // set up the resolved name on the path
    2239         1342 :   auto &nr_ctx = Resolver2_0::FinalizedNameResolutionContext::get ();
    2240              : 
    2241         1342 :   nr_ctx.map_usage (Resolver2_0::Usage (expr.get_mappings ().get_nodeid ()),
    2242         1342 :                     Resolver2_0::Definition (resolved_node_id),
    2243              :                     Resolver2_0::Namespace::Types);
    2244              : 
    2245              :   // return the result of the function back
    2246         1342 :   infered = function_ret_tyty;
    2247              : 
    2248         1342 :   return true;
    2249         4569 : }
    2250              : 
    2251              : HIR::PathIdentSegment
    2252        11674 : TypeCheckExpr::resolve_possible_fn_trait_call_method_name (
    2253              :   const TyTy::BaseType &receiver,
    2254              :   TyTy::TypeBoundPredicate *associated_predicate)
    2255              : {
    2256              :   // FIXME
    2257              :   // the logic to map the FnTrait to their respective call trait-item is
    2258              :   // duplicated over in the backend/rust-compile-expr.cc
    2259        11701 :   for (const auto &bound : receiver.get_specified_bounds ())
    2260              :     {
    2261           93 :       bool found_fn = bound.get_name ().compare ("Fn") == 0;
    2262           93 :       bool found_fn_mut = bound.get_name ().compare ("FnMut") == 0;
    2263           93 :       bool found_fn_once = bound.get_name ().compare ("FnOnce") == 0;
    2264              : 
    2265           93 :       if (found_fn)
    2266              :         {
    2267            0 :           *associated_predicate = bound;
    2268            0 :           return HIR::PathIdentSegment ("call");
    2269              :         }
    2270           93 :       else if (found_fn_mut)
    2271              :         {
    2272            0 :           *associated_predicate = bound;
    2273            0 :           return HIR::PathIdentSegment ("call_mut");
    2274              :         }
    2275           93 :       else if (found_fn_once)
    2276              :         {
    2277           66 :           *associated_predicate = bound;
    2278           66 :           return HIR::PathIdentSegment ("call_once");
    2279              :         }
    2280              :     }
    2281              : 
    2282        11608 :   if (receiver.is<TyTy::ReferenceType> ())
    2283              :     {
    2284            0 :       const auto &ref = static_cast<const TyTy::ReferenceType &> (receiver);
    2285            0 :       const auto &underlying = *ref.get_base ();
    2286            0 :       for (const auto &bound : underlying.get_specified_bounds ())
    2287              :         {
    2288            0 :           bool found_fn = bound.get_name ().compare ("Fn") == 0;
    2289            0 :           bool found_fn_mut = bound.get_name ().compare ("FnMut") == 0;
    2290            0 :           bool found_fn_once = bound.get_name ().compare ("FnOnce") == 0;
    2291              : 
    2292            0 :           if (found_fn)
    2293              :             {
    2294            0 :               *associated_predicate = bound;
    2295            0 :               return HIR::PathIdentSegment ("call");
    2296              :             }
    2297            0 :           else if (found_fn_mut)
    2298              :             {
    2299            0 :               *associated_predicate = bound;
    2300            0 :               return HIR::PathIdentSegment ("call_mut");
    2301              :             }
    2302            0 :           else if (found_fn_once)
    2303              :             {
    2304            0 :               *associated_predicate = bound;
    2305            0 :               return HIR::PathIdentSegment ("call_once");
    2306              :             }
    2307              :         }
    2308              :     }
    2309              : 
    2310              :   // nothing
    2311        11608 :   *associated_predicate = TyTy::TypeBoundPredicate::error ();
    2312        11608 :   return HIR::PathIdentSegment ("");
    2313              : }
    2314              : 
    2315              : bool
    2316        11674 : TypeCheckExpr::resolve_fn_trait_call (HIR::CallExpr &expr,
    2317              :                                       TyTy::BaseType *receiver_tyty,
    2318              :                                       TyTy::BaseType **result)
    2319              : {
    2320              :   // we turn this into a method call expr
    2321              :   // TODO: add implicit self argument (?)
    2322        11674 :   auto associated_predicate = TyTy::TypeBoundPredicate::error ();
    2323        11674 :   HIR::PathIdentSegment method_name
    2324              :     = resolve_possible_fn_trait_call_method_name (*receiver_tyty,
    2325        11674 :                                                   &associated_predicate);
    2326        11674 :   if (method_name.is_error () || associated_predicate.is_error ())
    2327              :     return false;
    2328              : 
    2329           66 :   auto candidates = MethodResolver::Probe (receiver_tyty, method_name);
    2330           66 :   if (candidates.empty ())
    2331              :     return false;
    2332              : 
    2333           66 :   if (candidates.size () > 1)
    2334              :     {
    2335            0 :       rich_location r (line_table, expr.get_locus ());
    2336            0 :       for (auto &c : candidates)
    2337            0 :         r.add_range (c.candidate.locus);
    2338              : 
    2339            0 :       rust_error_at (
    2340              :         r, "multiple candidates found for function trait method call %qs",
    2341            0 :         method_name.to_string ().c_str ());
    2342            0 :       return false;
    2343            0 :     }
    2344              : 
    2345              :   // FnOnce::Output is normalized lazily by normalize_projection's closure
    2346              :   // special-case; no explicit setup is required here.
    2347              : 
    2348           66 :   auto candidate = *candidates.begin ();
    2349           66 :   rust_debug_loc (expr.get_locus (),
    2350              :                   "resolved call-expr to fn trait: {%u} {%s}",
    2351              :                   candidate.candidate.ty->get_ref (),
    2352              :                   candidate.candidate.ty->debug_str ().c_str ());
    2353              : 
    2354              :   // Get the adjusted self
    2355           66 :   Adjuster adj (receiver_tyty);
    2356           66 :   TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments);
    2357              : 
    2358              :   // store the adjustments for code-generation to know what to do which must be
    2359              :   // stored onto the receiver to so as we don't trigger duplicate deref mappings
    2360              :   // ICE when an argument is a method call
    2361           66 :   HIR::Expr &fnexpr = expr.get_fnexpr ();
    2362           66 :   HirId autoderef_mappings_id = fnexpr.get_mappings ().get_hirid ();
    2363           66 :   context->insert_autoderef_mappings (autoderef_mappings_id,
    2364              :                                       std::move (candidate.adjustments));
    2365              : 
    2366           66 :   PathProbeCandidate &resolved_candidate = candidate.candidate;
    2367           66 :   TyTy::BaseType *lookup_tyty = candidate.candidate.ty;
    2368           66 :   NodeId resolved_node_id
    2369           66 :     = resolved_candidate.is_impl_candidate ()
    2370           66 :         ? resolved_candidate.item.impl.impl_item->get_impl_mappings ()
    2371            0 :             .get_nodeid ()
    2372           66 :         : resolved_candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
    2373              : 
    2374           66 :   if (lookup_tyty->get_kind () != TyTy::TypeKind::FNDEF)
    2375              :     {
    2376            0 :       rich_location r (line_table, expr.get_locus ());
    2377            0 :       r.add_range (resolved_candidate.locus);
    2378            0 :       rust_error_at (r, "associated impl item is not a method");
    2379            0 :       return false;
    2380            0 :     }
    2381              : 
    2382           66 :   TyTy::BaseType *lookup = lookup_tyty;
    2383           66 :   TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
    2384          132 :   if (!fn->is_method ())
    2385              :     {
    2386            0 :       rich_location r (line_table, expr.get_locus ());
    2387            0 :       r.add_range (resolved_candidate.locus);
    2388            0 :       rust_error_at (r, "associated function is not a method");
    2389            0 :       return false;
    2390            0 :     }
    2391              : 
    2392              :   // fn traits only support tuple argument passing so we need to implicitly set
    2393              :   // this up to get the same type checking we get in the rest of the pipeline
    2394              : 
    2395           66 :   std::vector<TyTy::TyVar> call_args;
    2396          132 :   for (auto &arg : expr.get_arguments ())
    2397              :     {
    2398           66 :       TyTy::BaseType *a = TypeCheckExpr::Resolve (*arg);
    2399           66 :       call_args.emplace_back (a->get_ref ());
    2400              :     }
    2401              : 
    2402              :   // crate implicit tuple
    2403           66 :   HirId implicit_arg_id = mappings.get_next_hir_id ();
    2404           66 :   Analysis::NodeMapping mapping (mappings.get_current_crate (), UNKNOWN_NODEID,
    2405           66 :                                  implicit_arg_id, UNKNOWN_LOCAL_DEFID);
    2406              : 
    2407           66 :   TyTy::TupleType *tuple
    2408           66 :     = new TyTy::TupleType (implicit_arg_id, expr.get_locus (), call_args);
    2409           66 :   context->insert_implicit_type (implicit_arg_id, tuple);
    2410              : 
    2411           66 :   std::vector<TyTy::Argument> args;
    2412           66 :   args.emplace_back (mapping, tuple,
    2413           66 :                      expr.get_locus () /*FIXME is there a better location*/);
    2414              : 
    2415           66 :   TyTy::BaseType *function_ret_tyty
    2416           66 :     = TyTy::TypeCheckMethodCallExpr::go (fn, expr.get_mappings (), args,
    2417              :                                          expr.get_locus (), expr.get_locus (),
    2418              :                                          adjusted_self, context);
    2419           66 :   if (function_ret_tyty == nullptr
    2420           66 :       || function_ret_tyty->get_kind () == TyTy::TypeKind::ERROR)
    2421              :     {
    2422            0 :       rust_error_at (expr.get_locus (),
    2423              :                      "failed check fn trait call-expr MethodCallExpr");
    2424            0 :       return false;
    2425              :     }
    2426              : 
    2427              :   // store the expected fntype
    2428           66 :   context->insert_operator_overload (expr.get_mappings ().get_hirid (), fn);
    2429              : 
    2430              :   // set up the resolved name on the path
    2431           66 :   auto &nr_ctx = Resolver2_0::FinalizedNameResolutionContext::get ();
    2432              : 
    2433              :   // TODO: What namespace to use for inserting and looking up here? It's a trait
    2434              :   // call, so NS::Types is right?
    2435              : 
    2436           66 :   auto existing = nr_ctx.lookup (expr.get_mappings ().get_nodeid (),
    2437              :                                  Resolver2_0::Namespace::Types);
    2438           66 :   if (existing)
    2439            9 :     rust_assert (*existing == resolved_node_id);
    2440              :   else
    2441           57 :     nr_ctx.map_usage (Resolver2_0::Usage (expr.get_mappings ().get_nodeid ()),
    2442           57 :                       Resolver2_0::Definition (resolved_node_id),
    2443              :                       Resolver2_0::Namespace::Types);
    2444              : 
    2445              :   // return the result of the function back
    2446           66 :   auto mono = function_ret_tyty->monomorphized_clone ();
    2447           66 :   *result = mono;
    2448              : 
    2449           66 :   return true;
    2450        11872 : }
    2451              : 
    2452              : bool
    2453         8406 : TypeCheckExpr::validate_arithmetic_type (
    2454              :   const TyTy::BaseType *tyty, HIR::ArithmeticOrLogicalExpr::ExprType expr_type)
    2455              : {
    2456         8406 :   auto type = tyty->destructure ();
    2457         8406 :   if (type->get_kind () == TyTy::TypeKind::CONST)
    2458              :     {
    2459           15 :       auto base_const = type->as_const_type ();
    2460           15 :       type = base_const->get_specified_type ();
    2461              :     }
    2462              : 
    2463              :   // https://doc.rust-lang.org/reference/expressions/operator-expr.html#arithmetic-and-logical-binary-operators
    2464              :   // this will change later when traits are added
    2465         8406 :   switch (expr_type)
    2466              :     {
    2467         7190 :     case ArithmeticOrLogicalOperator::ADD:
    2468         7190 :     case ArithmeticOrLogicalOperator::SUBTRACT:
    2469         7190 :     case ArithmeticOrLogicalOperator::MULTIPLY:
    2470         7190 :     case ArithmeticOrLogicalOperator::DIVIDE:
    2471         7190 :     case ArithmeticOrLogicalOperator::MODULUS:
    2472         7190 :       return (type->get_kind () == TyTy::TypeKind::INT)
    2473         5463 :              || (type->get_kind () == TyTy::TypeKind::UINT)
    2474         4419 :              || (type->get_kind () == TyTy::TypeKind::FLOAT)
    2475         3971 :              || (type->get_kind () == TyTy::TypeKind::USIZE)
    2476         3275 :              || (type->get_kind () == TyTy::TypeKind::ISIZE)
    2477         3193 :              || (type->get_kind () == TyTy::TypeKind::INFER
    2478         3190 :                  && (((const TyTy::InferType *) type)->get_infer_kind ()
    2479              :                      == TyTy::InferType::INTEGRAL))
    2480         7230 :              || (type->get_kind () == TyTy::TypeKind::INFER
    2481           37 :                  && (((const TyTy::InferType *) type)->get_infer_kind ()
    2482              :                      == TyTy::InferType::FLOAT));
    2483              : 
    2484              :       // integers or bools
    2485         1050 :     case ArithmeticOrLogicalOperator::BITWISE_AND:
    2486         1050 :     case ArithmeticOrLogicalOperator::BITWISE_OR:
    2487         1050 :     case ArithmeticOrLogicalOperator::BITWISE_XOR:
    2488         1050 :       return (type->get_kind () == TyTy::TypeKind::INT)
    2489          973 :              || (type->get_kind () == TyTy::TypeKind::UINT)
    2490          173 :              || (type->get_kind () == TyTy::TypeKind::USIZE)
    2491          166 :              || (type->get_kind () == TyTy::TypeKind::ISIZE)
    2492          166 :              || (type->get_kind () == TyTy::TypeKind::BOOL)
    2493         1174 :              || (type->get_kind () == TyTy::TypeKind::INFER
    2494          124 :                  && (((const TyTy::InferType *) type)->get_infer_kind ()
    2495              :                      == TyTy::InferType::INTEGRAL));
    2496              : 
    2497              :       // integers only
    2498          166 :     case ArithmeticOrLogicalOperator::LEFT_SHIFT:
    2499          166 :     case ArithmeticOrLogicalOperator::RIGHT_SHIFT:
    2500          166 :       return (type->get_kind () == TyTy::TypeKind::INT)
    2501          151 :              || (type->get_kind () == TyTy::TypeKind::UINT)
    2502           93 :              || (type->get_kind () == TyTy::TypeKind::USIZE)
    2503           91 :              || (type->get_kind () == TyTy::TypeKind::ISIZE)
    2504          257 :              || (type->get_kind () == TyTy::TypeKind::INFER
    2505           91 :                  && (((const TyTy::InferType *) type)->get_infer_kind ()
    2506              :                      == TyTy::InferType::INTEGRAL));
    2507              :     }
    2508              : 
    2509            0 :   rust_unreachable ();
    2510              :   return false;
    2511              : }
    2512              : 
    2513              : } // namespace Resolver
    2514              : } // namespace Rust
        

Generated by: LCOV version 2.4-beta

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