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