LCOV - code coverage report
Current view: top level - gcc/rust/backend - rust-compile-expr.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 94.1 % 1496 1408
Test Date: 2026-06-20 15:32:29 Functions: 98.6 % 73 72
Legend: Lines:     hit not hit

            Line data    Source code
       1              : // Copyright (C) 2020-2026 Free Software Foundation, Inc.
       2              : 
       3              : // This file is part of GCC.
       4              : 
       5              : // GCC is free software; you can redistribute it and/or modify it under
       6              : // the terms of the GNU General Public License as published by the Free
       7              : // Software Foundation; either version 3, or (at your option) any later
       8              : // version.
       9              : 
      10              : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      11              : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12              : // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      13              : // for more details.
      14              : 
      15              : // You should have received a copy of the GNU General Public License
      16              : // along with GCC; see the file COPYING3.  If not see
      17              : // <http://www.gnu.org/licenses/>.
      18              : 
      19              : #include "rust-compile-expr.h"
      20              : #include "rust-backend.h"
      21              : #include "rust-compile-context.h"
      22              : #include "rust-compile-type.h"
      23              : #include "rust-compile-struct-field-expr.h"
      24              : #include "rust-compile-pattern.h"
      25              : #include "rust-compile-resolve-path.h"
      26              : #include "rust-compile-block.h"
      27              : #include "rust-compile-implitem.h"
      28              : #include "rust-constexpr.h"
      29              : #include "rust-compile-type.h"
      30              : #include "rust-gcc.h"
      31              : #include "rust-compile-asm.h"
      32              : #include "fold-const.h"
      33              : #include "realmpfr.h"
      34              : #include "convert.h"
      35              : #include "print-tree.h"
      36              : #include "rust-hir-bound.h"
      37              : #include "rust-hir-expr.h"
      38              : #include "rust-system.h"
      39              : #include "rust-tree.h"
      40              : #include "rust-tyty.h"
      41              : #include "tree-core.h"
      42              : 
      43              : namespace Rust {
      44              : namespace Compile {
      45              : 
      46       121056 : CompileExpr::CompileExpr (Context *ctx)
      47       121056 :   : HIRCompileBase (ctx), translated (error_mark_node)
      48       121056 : {}
      49              : 
      50              : tree
      51       121056 : CompileExpr::Compile (HIR::Expr &expr, Context *ctx)
      52              : {
      53       121056 :   CompileExpr compiler (ctx);
      54       121056 :   expr.accept_vis (compiler);
      55       121056 :   return compiler.translated;
      56       121056 : }
      57              : 
      58              : void
      59          884 : CompileExpr::visit (HIR::TupleIndexExpr &expr)
      60              : {
      61          884 :   HIR::Expr &tuple_expr = expr.get_tuple_expr ();
      62          884 :   TupleIndex index = expr.get_tuple_index ();
      63              : 
      64          884 :   tree receiver_ref = CompileExpr::Compile (tuple_expr, ctx);
      65              : 
      66          884 :   TyTy::BaseType *tuple_expr_ty = nullptr;
      67          884 :   bool ok
      68          884 :     = ctx->get_tyctx ()->lookup_type (tuple_expr.get_mappings ().get_hirid (),
      69              :                                       &tuple_expr_ty);
      70          884 :   rust_assert (ok);
      71              : 
      72              :   // do we need to add an indirect reference
      73          884 :   if (tuple_expr_ty->get_kind () == TyTy::TypeKind::REF)
      74              :     {
      75          299 :       tree indirect = indirect_expression (receiver_ref, expr.get_locus ());
      76          299 :       receiver_ref = indirect;
      77              :     }
      78              : 
      79          884 :   translated
      80          884 :     = Backend::struct_field_expression (receiver_ref, index, expr.get_locus ());
      81          884 : }
      82              : 
      83              : void
      84          570 : CompileExpr::visit (HIR::TupleExpr &expr)
      85              : {
      86          570 :   if (expr.is_unit ())
      87              :     {
      88          139 :       translated = unit_expression (expr.get_locus ());
      89          139 :       return;
      90              :     }
      91              : 
      92          431 :   TyTy::BaseType *tyty = nullptr;
      93          431 :   if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
      94              :                                        &tyty))
      95              :     {
      96            0 :       rust_fatal_error (expr.get_locus (),
      97              :                         "did not resolve type for this TupleExpr");
      98              :       return;
      99              :     }
     100              : 
     101          431 :   tree tuple_type = TyTyResolveCompile::compile (ctx, tyty);
     102          431 :   rust_assert (tuple_type != nullptr);
     103              : 
     104              :   // this assumes all fields are in order from type resolution
     105          431 :   std::vector<tree> vals;
     106         1428 :   for (auto &elem : expr.get_tuple_elems ())
     107              :     {
     108          997 :       auto e = CompileExpr::Compile (*elem, ctx);
     109          997 :       vals.push_back (e);
     110              :     }
     111              : 
     112          431 :   translated = Backend::constructor_expression (tuple_type, false, vals, -1,
     113              :                                                 expr.get_locus ());
     114          431 : }
     115              : 
     116              : void
     117          522 : CompileExpr::visit (HIR::ReturnExpr &expr)
     118              : {
     119          522 :   auto fncontext = ctx->peek_fn ();
     120              : 
     121          522 :   tree return_value = expr.has_return_expr ()
     122          522 :                         ? CompileExpr::Compile (expr.get_expr (), ctx)
     123           38 :                         : unit_expression (expr.get_locus ());
     124              : 
     125          522 :   if (expr.has_return_expr ())
     126              :     {
     127          484 :       HirId id = expr.get_mappings ().get_hirid ();
     128          484 :       location_t rvalue_locus = expr.return_expr->get_locus ();
     129              : 
     130          484 :       TyTy::BaseType *expected = fncontext.retty;
     131          484 :       location_t lvalue_locus
     132          484 :         = ctx->get_mappings ().lookup_location (expected->get_ref ());
     133              : 
     134          484 :       TyTy::BaseType *actual = nullptr;
     135          484 :       bool ok = ctx->get_tyctx ()->lookup_type (
     136          484 :         expr.return_expr->get_mappings ().get_hirid (), &actual);
     137          484 :       rust_assert (ok);
     138              : 
     139          484 :       return_value = coercion_site (id, return_value, actual, expected,
     140              :                                     lvalue_locus, rvalue_locus);
     141              :     }
     142              : 
     143          522 :   tree return_stmt = Backend::return_statement (fncontext.fndecl, return_value,
     144              :                                                 expr.get_locus ());
     145          522 :   ctx->add_statement (return_stmt);
     146          522 : }
     147              : 
     148              : void
     149         3404 : CompileExpr::visit (HIR::ArithmeticOrLogicalExpr &expr)
     150              : {
     151         3404 :   auto op = expr.get_expr_type ();
     152         3404 :   auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx);
     153         3404 :   auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx);
     154              : 
     155              :   // this might be an operator overload situation lets check
     156         3404 :   TyTy::FnType *fntype;
     157         3404 :   bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload (
     158         3404 :     expr.get_mappings ().get_hirid (), &fntype);
     159         3404 :   if (is_op_overload)
     160              :     {
     161          166 :       auto lang_item_type
     162          166 :         = LangItem::OperatorToLangItem (expr.get_expr_type ());
     163          166 :       translated = resolve_operator_overload (
     164          332 :         lang_item_type, expr, lhs, rhs, expr.get_lhs (),
     165          166 :         tl::optional<std::reference_wrapper<HIR::Expr>> (expr.get_rhs ()));
     166          439 :       return;
     167              :     }
     168              : 
     169         3238 :   bool can_generate_overflow_checks
     170         3238 :     = (ctx->in_fn () && !ctx->const_context_p ()) && flag_overflow_checks;
     171         3238 :   if (!can_generate_overflow_checks)
     172              :     {
     173          273 :       translated
     174          273 :         = Backend::arithmetic_or_logical_expression (op, lhs, rhs,
     175              :                                                      expr.get_locus ());
     176          273 :       return;
     177              :     }
     178              : 
     179         2965 :   auto receiver_tmp = NULL_TREE;
     180         2965 :   Bvariable *receiver
     181         2965 :     = Backend::temporary_variable (ctx->peek_fn ().fndecl, NULL_TREE,
     182         2965 :                                    TREE_TYPE (lhs), lhs, true,
     183              :                                    expr.get_locus (), &receiver_tmp);
     184         2965 :   auto check
     185         2965 :     = Backend::arithmetic_or_logical_expression_checked (op, lhs, rhs,
     186              :                                                          expr.get_locus (),
     187              :                                                          receiver);
     188              : 
     189         2965 :   ctx->add_statement (check);
     190         2965 :   translated = receiver->get_tree (expr.get_locus ());
     191              : }
     192              : 
     193              : void
     194          753 : CompileExpr::visit (HIR::CompoundAssignmentExpr &expr)
     195              : {
     196          753 :   auto op = expr.get_expr_type ();
     197          753 :   tree lhs = CompileExpr::Compile (expr.get_lhs (), ctx);
     198          753 :   tree rhs = CompileExpr::Compile (expr.get_rhs (), ctx);
     199          753 :   tree compound_assignment = NULL_TREE;
     200              :   // this might be an operator overload situation lets check
     201          753 :   TyTy::FnType *fntype;
     202          753 :   bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload (
     203          753 :     expr.get_mappings ().get_hirid (), &fntype);
     204          753 :   if (is_op_overload)
     205              :     {
     206           14 :       auto lang_item_type = LangItem::CompoundAssignmentOperatorToLangItem (
     207              :         expr.get_expr_type ());
     208           14 :       compound_assignment
     209           14 :         = resolve_operator_overload (lang_item_type, expr, lhs, rhs,
     210           14 :                                      expr.get_lhs (), expr.get_rhs ());
     211              :     }
     212          739 :   else if (ctx->in_fn () && !ctx->const_context_p ())
     213              :     {
     214          736 :       tree tmp = NULL_TREE;
     215          736 :       Bvariable *receiver
     216          736 :         = Backend::temporary_variable (ctx->peek_fn ().fndecl, NULL_TREE,
     217          736 :                                        TREE_TYPE (lhs), lhs, true,
     218              :                                        expr.get_locus (), &tmp);
     219          736 :       tree check
     220          736 :         = Backend::arithmetic_or_logical_expression_checked (op, lhs, rhs,
     221              :                                                              expr.get_locus (),
     222              :                                                              receiver);
     223          736 :       ctx->add_statement (check);
     224          736 :       compound_assignment
     225          736 :         = Backend::assignment_statement (lhs,
     226              :                                          receiver->get_tree (expr.get_locus ()),
     227              :                                          expr.get_locus ());
     228              :     }
     229              :   else
     230              :     {
     231            3 :       tree expr_tree
     232            3 :         = Backend::arithmetic_or_logical_expression (op, lhs, rhs,
     233              :                                                      expr.get_locus ());
     234            3 :       compound_assignment
     235            3 :         = Backend::assignment_statement (lhs, expr_tree, expr.get_locus ());
     236              :     }
     237          753 :   ctx->add_statement (compound_assignment);
     238          753 :   translated = unit_expression (expr.get_locus ());
     239          753 : }
     240              : 
     241              : void
     242          833 : CompileExpr::visit (HIR::NegationExpr &expr)
     243              : {
     244          833 :   auto op = expr.get_expr_type ();
     245              : 
     246          833 :   auto &literal_expr = expr.get_expr ();
     247              : 
     248              :   // If it's a negated integer/float literal, we can return early
     249          833 :   if (op == NegationOperator::NEGATE
     250          833 :       && literal_expr.get_expression_type () == HIR::Expr::ExprType::Lit)
     251              :     {
     252          627 :       auto &new_literal_expr = static_cast<HIR::LiteralExpr &> (literal_expr);
     253          627 :       auto lit_type = new_literal_expr.get_lit_type ();
     254          627 :       if (lit_type == HIR::Literal::LitType::INT
     255          627 :           || lit_type == HIR::Literal::LitType::FLOAT)
     256              :         {
     257          627 :           new_literal_expr.set_negative ();
     258          627 :           translated = CompileExpr::Compile (literal_expr, ctx);
     259          641 :           return;
     260              :         }
     261              :     }
     262              : 
     263          206 :   auto negated_expr = CompileExpr::Compile (literal_expr, ctx);
     264          206 :   auto location = expr.get_locus ();
     265              : 
     266              :   // this might be an operator overload situation lets check
     267          206 :   TyTy::FnType *fntype;
     268          206 :   bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload (
     269          206 :     expr.get_mappings ().get_hirid (), &fntype);
     270          206 :   if (is_op_overload)
     271              :     {
     272           14 :       auto lang_item_type = LangItem::NegationOperatorToLangItem (op);
     273           14 :       translated
     274           14 :         = resolve_operator_overload (lang_item_type, expr, negated_expr,
     275              :                                      nullptr, expr.get_expr (), tl::nullopt);
     276           14 :       return;
     277              :     }
     278              : 
     279          192 :   translated = Backend::negation_expression (op, negated_expr, location);
     280              : }
     281              : 
     282              : void
     283         3312 : CompileExpr::visit (HIR::ComparisonExpr &expr)
     284              : {
     285         3312 :   auto op = expr.get_expr_type ();
     286         3312 :   auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx);
     287         3312 :   auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx);
     288         3312 :   auto location = expr.get_locus ();
     289              : 
     290              :   // this might be an operator overload situation lets check
     291         3312 :   TyTy::FnType *fntype;
     292         3312 :   bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload (
     293         3312 :     expr.get_mappings ().get_hirid (), &fntype);
     294         3312 :   if (is_op_overload)
     295              :     {
     296          840 :       auto seg_name = LangItem::ComparisonToSegment (expr.get_expr_type ());
     297         1680 :       auto segment = HIR::PathIdentSegment (seg_name);
     298          840 :       auto lang_item_type
     299          840 :         = LangItem::ComparisonToLangItem (expr.get_expr_type ());
     300              : 
     301          840 :       rhs = address_expression (rhs, EXPR_LOCATION (rhs));
     302              : 
     303         1680 :       translated = resolve_operator_overload (
     304         1680 :         lang_item_type, expr, lhs, rhs, expr.get_lhs (),
     305          840 :         tl::optional<std::reference_wrapper<HIR::Expr>> (expr.get_rhs ()),
     306              :         segment);
     307          840 :       return;
     308          840 :     }
     309              : 
     310         2472 :   translated = Backend::comparison_expression (op, lhs, rhs, location);
     311              : }
     312              : 
     313              : void
     314          377 : CompileExpr::visit (HIR::LazyBooleanExpr &expr)
     315              : {
     316          377 :   auto op = expr.get_expr_type ();
     317          377 :   auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx);
     318          377 :   auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx);
     319          377 :   auto location = expr.get_locus ();
     320              : 
     321          377 :   translated = Backend::lazy_boolean_expression (op, lhs, rhs, location);
     322          377 : }
     323              : 
     324              : void
     325         4860 : CompileExpr::visit (HIR::TypeCastExpr &expr)
     326              : {
     327         4860 :   TyTy::BaseType *type_to_cast_to_ty = nullptr;
     328         4860 :   if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
     329              :                                        &type_to_cast_to_ty))
     330              :     {
     331            0 :       translated = error_mark_node;
     332            0 :       return;
     333              :     }
     334              : 
     335         4860 :   TyTy::BaseType *casted_tyty = nullptr;
     336         4860 :   if (!ctx->get_tyctx ()->lookup_type (
     337         4860 :         expr.get_casted_expr ().get_mappings ().get_hirid (), &casted_tyty))
     338              :     {
     339            0 :       translated = error_mark_node;
     340            0 :       return;
     341              :     }
     342              : 
     343         4860 :   auto type_to_cast_to = TyTyResolveCompile::compile (ctx, type_to_cast_to_ty);
     344         4860 :   auto casted_expr = CompileExpr::Compile (expr.get_casted_expr (), ctx);
     345              : 
     346         4860 :   std::vector<Resolver::Adjustment> *adjustments = nullptr;
     347         4860 :   bool ok = ctx->get_tyctx ()->lookup_cast_autoderef_mappings (
     348         4860 :     expr.get_mappings ().get_hirid (), &adjustments);
     349         4860 :   if (ok)
     350              :     {
     351         4860 :       casted_expr
     352         4860 :         = resolve_adjustements (*adjustments, casted_expr, expr.get_locus ());
     353              :     }
     354              : 
     355         4860 :   translated
     356         4860 :     = type_cast_expression (type_to_cast_to, casted_expr, expr.get_locus ());
     357              : }
     358              : 
     359              : void
     360         1217 : CompileExpr::visit (HIR::IfExpr &expr)
     361              : {
     362         1217 :   auto stmt = CompileConditionalBlocks::compile (&expr, ctx, nullptr);
     363         1217 :   ctx->add_statement (stmt);
     364         1217 :   translated = unit_expression (expr.get_locus ());
     365         1217 : }
     366              : 
     367              : void
     368           26 : CompileExpr::visit (HIR::InlineAsm &expr)
     369              : {
     370           26 :   CompileAsm asm_codegen (ctx);
     371           26 :   ctx->add_statement (asm_codegen.tree_codegen_asm (expr));
     372           26 :   translated = unit_expression (expr.get_locus ());
     373           26 : }
     374              : 
     375              : void
     376            2 : CompileExpr::visit (HIR::LlvmInlineAsm &expr)
     377              : {
     378            2 :   CompileLlvmAsm asm_codegen (ctx);
     379            2 :   ctx->add_statement (asm_codegen.tree_codegen_asm (expr));
     380            2 :   translated = unit_expression (expr.get_locus ());
     381            2 : }
     382              : 
     383              : void
     384           14 : CompileExpr::visit (HIR::OffsetOf &expr)
     385              : {
     386           14 :   TyTy::BaseType *type = nullptr;
     387           14 :   if (!ctx->get_tyctx ()->lookup_type (
     388           14 :         expr.get_type ().get_mappings ().get_hirid (), &type))
     389              :     {
     390            0 :       translated = error_mark_node;
     391            0 :       return;
     392              :     }
     393              : 
     394           14 :   auto compiled_ty = TyTyResolveCompile::compile (ctx, type);
     395              : 
     396           14 :   rust_assert (TREE_CODE (compiled_ty) == RECORD_TYPE);
     397              : 
     398              :   // Create an identifier node for the field
     399           14 :   auto field_id = Backend::get_identifier_node (expr.get_field ().as_string ());
     400              : 
     401              :   // And now look it up and get its value for `byte_position`
     402           14 :   auto field = Backend::lookup_field (compiled_ty, field_id);
     403           14 :   auto field_value = TREE_VALUE (field);
     404              : 
     405           14 :   translated = byte_position (field_value);
     406              : }
     407              : 
     408              : void
     409          807 : CompileExpr::visit (HIR::IfExprConseqElse &expr)
     410              : {
     411          807 :   TyTy::BaseType *if_type = nullptr;
     412          807 :   if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
     413              :                                        &if_type))
     414              :     {
     415            0 :       rust_error_at (expr.get_locus (),
     416              :                      "failed to lookup type of IfExprConseqElse");
     417            0 :       return;
     418              :     }
     419              : 
     420          807 :   Bvariable *tmp = NULL;
     421          807 :   fncontext fnctx = ctx->peek_fn ();
     422          807 :   tree enclosing_scope = ctx->peek_enclosing_scope ();
     423          807 :   tree block_type = TyTyResolveCompile::compile (ctx, if_type);
     424              : 
     425          807 :   bool is_address_taken = false;
     426          807 :   tree ret_var_stmt = nullptr;
     427          807 :   tmp = Backend::temporary_variable (fnctx.fndecl, enclosing_scope, block_type,
     428              :                                      NULL, is_address_taken, expr.get_locus (),
     429              :                                      &ret_var_stmt);
     430          807 :   ctx->add_statement (ret_var_stmt);
     431              : 
     432          807 :   auto stmt = CompileConditionalBlocks::compile (&expr, ctx, tmp);
     433          807 :   ctx->add_statement (stmt);
     434              : 
     435          807 :   translated = Backend::var_expression (tmp, expr.get_locus ());
     436              : }
     437              : 
     438              : void
     439         4745 : CompileExpr::visit (HIR::BlockExpr &expr)
     440              : {
     441         4745 :   TyTy::BaseType *block_tyty = nullptr;
     442         4745 :   if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
     443              :                                        &block_tyty))
     444              :     {
     445            0 :       rust_error_at (expr.get_locus (), "failed to lookup type of BlockExpr");
     446            0 :       return;
     447              :     }
     448              : 
     449         4745 :   Bvariable *tmp = NULL;
     450         4745 :   fncontext fnctx = ctx->peek_fn ();
     451         4745 :   tree enclosing_scope = ctx->peek_enclosing_scope ();
     452         4745 :   tree block_type = TyTyResolveCompile::compile (ctx, block_tyty);
     453         4745 :   tree block_label = NULL_TREE;
     454              : 
     455         4745 :   bool is_address_taken = false;
     456         4745 :   tree ret_var_stmt = nullptr;
     457         4745 :   tmp = Backend::temporary_variable (fnctx.fndecl, enclosing_scope, block_type,
     458              :                                      NULL, is_address_taken, expr.get_locus (),
     459              :                                      &ret_var_stmt);
     460              : 
     461         4745 :   ctx->add_statement (ret_var_stmt);
     462              : 
     463         4745 :   if (expr.has_label ())
     464              :     {
     465            2 :       ctx->insert_var_decl (
     466            2 :         expr.get_label ().get_lifetime ().get_mappings ().get_hirid (), tmp);
     467            2 :       block_label = construct_block_label (expr);
     468              :     }
     469              : 
     470         4745 :   auto block_stmt = CompileBlock::compile (expr, ctx, tmp);
     471         4745 :   rust_assert (TREE_CODE (block_stmt) == BIND_EXPR);
     472         4745 :   ctx->add_statement (block_stmt);
     473              : 
     474         4745 :   if (block_label != NULL_TREE)
     475              :     {
     476            2 :       ctx->add_statement (block_label);
     477              :     }
     478         4745 :   translated = Backend::var_expression (tmp, expr.get_locus ());
     479              : }
     480              : 
     481              : void
     482          648 : CompileExpr::visit (HIR::AnonConst &expr)
     483              : {
     484          648 :   expr.get_inner_expr ().accept_vis (*this);
     485          648 : }
     486              : 
     487              : void
     488           15 : CompileExpr::visit (HIR::ConstBlock &expr)
     489              : {
     490           15 :   expr.get_const_expr ().accept_vis (*this);
     491           15 : }
     492              : 
     493              : void
     494         3330 : CompileExpr::visit (HIR::UnsafeBlockExpr &expr)
     495              : {
     496         3330 :   expr.get_block_expr ().accept_vis (*this);
     497         3330 : }
     498              : 
     499              : void
     500           79 : CompileExpr::visit (HIR::StructExprStruct &struct_expr)
     501              : {
     502           79 :   TyTy::BaseType *tyty = nullptr;
     503           79 :   if (!ctx->get_tyctx ()->lookup_type (struct_expr.get_mappings ().get_hirid (),
     504              :                                        &tyty))
     505              :     {
     506            0 :       rust_error_at (struct_expr.get_locus (), "unknown type");
     507            0 :       return;
     508              :     }
     509              : 
     510           79 :   TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (tyty);
     511           79 :   TyTy::VariantDef *variant = nullptr;
     512           79 :   if (adt->is_enum ())
     513              :     {
     514              :       // unwrap variant and ensure that it can be resolved
     515            3 :       HirId variant_id;
     516            3 :       bool ok = ctx->get_tyctx ()->lookup_variant_definition (
     517            3 :         struct_expr.get_struct_name ().get_mappings ().get_hirid (),
     518              :         &variant_id);
     519            3 :       rust_assert (ok);
     520              : 
     521            3 :       ok = adt->lookup_variant_by_id (variant_id, &variant);
     522            3 :       rust_assert (ok);
     523              :     }
     524              :   else
     525              :     {
     526           76 :       rust_assert (tyty->is_unit ());
     527              :     }
     528              : 
     529           79 :   translated = unit_expression (struct_expr.get_locus ());
     530              : }
     531              : 
     532              : void
     533         1242 : CompileExpr::visit (HIR::StructExprStructFields &struct_expr)
     534              : {
     535         1242 :   TyTy::BaseType *tyty = nullptr;
     536         1242 :   if (!ctx->get_tyctx ()->lookup_type (struct_expr.get_mappings ().get_hirid (),
     537              :                                        &tyty))
     538              :     {
     539            0 :       rust_error_at (struct_expr.get_locus (), "unknown type");
     540         1156 :       return;
     541              :     }
     542         1242 :   if (!tyty->is<TyTy::ADTType> ())
     543              :     return;
     544              : 
     545              :   // it must be an ADT
     546         1242 :   rust_assert (tyty->get_kind () == TyTy::TypeKind::ADT);
     547         1242 :   TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (tyty);
     548              : 
     549              :   // what variant is it?
     550         1242 :   int union_disriminator = struct_expr.union_index;
     551         1242 :   TyTy::VariantDef *variant = nullptr;
     552         1242 :   if (!adt->is_enum ())
     553              :     {
     554         1156 :       rust_assert (adt->number_of_variants () == 1);
     555         1156 :       variant = adt->get_variants ().at (0);
     556              :     }
     557              :   else
     558              :     {
     559           86 :       HirId variant_id;
     560           86 :       bool ok = ctx->get_tyctx ()->lookup_variant_definition (
     561           86 :         struct_expr.get_struct_name ().get_mappings ().get_hirid (),
     562              :         &variant_id);
     563           86 :       rust_assert (ok);
     564              : 
     565           86 :       ok
     566           86 :         = adt->lookup_variant_by_id (variant_id, &variant, &union_disriminator);
     567           86 :       rust_assert (ok);
     568              :     }
     569              : 
     570              :   // compile it
     571         1242 :   tree compiled_adt_type = TyTyResolveCompile::compile (ctx, tyty);
     572              : 
     573         1242 :   std::vector<tree> arguments;
     574         1242 :   if (adt->is_union ())
     575              :     {
     576          100 :       rust_assert (struct_expr.get_fields ().size () == 1);
     577              : 
     578              :       // assignments are coercion sites so lets convert the rvalue if
     579              :       // necessary
     580          100 :       auto respective_field = variant->get_field_at_index (union_disriminator);
     581          100 :       auto expected = respective_field->get_field_type ();
     582              : 
     583              :       // process arguments
     584          100 :       auto &argument = struct_expr.get_fields ().at (0);
     585          100 :       auto lvalue_locus
     586          100 :         = ctx->get_mappings ().lookup_location (expected->get_ty_ref ());
     587          100 :       auto rvalue_locus = argument->get_locus ();
     588          100 :       auto rvalue = CompileStructExprField::Compile (*argument, ctx);
     589              : 
     590          100 :       TyTy::BaseType *actual = nullptr;
     591          100 :       bool ok = ctx->get_tyctx ()->lookup_type (
     592          100 :         argument->get_mappings ().get_hirid (), &actual);
     593              : 
     594          100 :       if (ok)
     595              :         {
     596          100 :           rvalue
     597          100 :             = coercion_site (argument->get_mappings ().get_hirid (), rvalue,
     598              :                              actual, expected, lvalue_locus, rvalue_locus);
     599              :         }
     600              : 
     601              :       // add it to the list
     602          100 :       arguments.push_back (rvalue);
     603              :     }
     604              :   else
     605              :     {
     606              :       // this assumes all fields are in order from type resolution and if a
     607              :       // base struct was specified those fields are filed via accessors
     608         3910 :       for (size_t i = 0; i < struct_expr.get_fields ().size (); i++)
     609              :         {
     610              :           // assignments are coercion sites so lets convert the rvalue if
     611              :           // necessary
     612         2768 :           auto respective_field = variant->get_field_at_index (i);
     613         2768 :           auto expected = respective_field->get_field_type ();
     614              : 
     615              :           // process arguments
     616         2768 :           auto &argument = struct_expr.get_fields ().at (i);
     617         2768 :           auto lvalue_locus
     618         2768 :             = ctx->get_mappings ().lookup_location (expected->get_ty_ref ());
     619         2768 :           auto rvalue_locus = argument->get_locus ();
     620         2768 :           auto rvalue = CompileStructExprField::Compile (*argument, ctx);
     621              : 
     622         2768 :           TyTy::BaseType *actual = nullptr;
     623         2768 :           bool ok = ctx->get_tyctx ()->lookup_type (
     624         2768 :             argument->get_mappings ().get_hirid (), &actual);
     625              : 
     626              :           // coerce it if required/possible see
     627              :           // compile/torture/struct_base_init_1.rs
     628         2768 :           if (ok)
     629              :             {
     630         2152 :               rvalue
     631         2152 :                 = coercion_site (argument->get_mappings ().get_hirid (), rvalue,
     632              :                                  actual, expected, lvalue_locus, rvalue_locus);
     633              :             }
     634              : 
     635              :           // add it to the list
     636         2768 :           arguments.push_back (rvalue);
     637              :         }
     638              :     }
     639              : 
     640         1242 :   if (!adt->is_enum ())
     641              :     {
     642         1156 :       translated
     643         1156 :         = Backend::constructor_expression (compiled_adt_type, adt->is_enum (),
     644              :                                            arguments, union_disriminator,
     645              :                                            struct_expr.get_locus ());
     646         1156 :       return;
     647              :     }
     648              : 
     649           86 :   HIR::Expr &discrim_expr = variant->get_discriminant ();
     650           86 :   tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx);
     651           86 :   tree folded_discrim_expr = fold_expr (discrim_expr_node);
     652           86 :   tree qualifier = folded_discrim_expr;
     653              : 
     654           86 :   tree enum_root_files = TYPE_FIELDS (compiled_adt_type);
     655           86 :   tree payload_root = DECL_CHAIN (enum_root_files);
     656              : 
     657           86 :   tree payload = Backend::constructor_expression (TREE_TYPE (payload_root),
     658           86 :                                                   adt->is_enum (), arguments,
     659              :                                                   union_disriminator,
     660              :                                                   struct_expr.get_locus ());
     661              : 
     662           86 :   std::vector<tree> ctor_arguments = {qualifier, payload};
     663              : 
     664           86 :   translated
     665           86 :     = Backend::constructor_expression (compiled_adt_type, 0, ctor_arguments, -1,
     666              :                                        struct_expr.get_locus ());
     667         1242 : }
     668              : 
     669              : void
     670          333 : CompileExpr::visit (HIR::GroupedExpr &expr)
     671              : {
     672          333 :   translated = CompileExpr::Compile (expr.get_expr_in_parens (), ctx);
     673          333 : }
     674              : 
     675              : void
     676         5588 : CompileExpr::visit (HIR::FieldAccessExpr &expr)
     677              : {
     678         5588 :   HIR::Expr &receiver_expr = expr.get_receiver_expr ();
     679         5588 :   tree receiver_ref = CompileExpr::Compile (receiver_expr, ctx);
     680              : 
     681              :   // resolve the receiver back to ADT type
     682         5588 :   TyTy::BaseType *receiver = nullptr;
     683         5588 :   if (!ctx->get_tyctx ()->lookup_type (
     684         5588 :         expr.get_receiver_expr ().get_mappings ().get_hirid (), &receiver))
     685              :     {
     686            0 :       rust_error_at (expr.get_receiver_expr ().get_locus (),
     687              :                      "unresolved type for receiver");
     688            0 :       return;
     689              :     }
     690              : 
     691         5588 :   size_t field_index = 0;
     692         5588 :   if (receiver->get_kind () == TyTy::TypeKind::ADT)
     693              :     {
     694         2038 :       TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (receiver);
     695         2038 :       rust_assert (!adt->is_enum ());
     696         2038 :       rust_assert (adt->number_of_variants () == 1);
     697              : 
     698         2038 :       TyTy::VariantDef *variant = adt->get_variants ().at (0);
     699         2038 :       bool ok = variant->lookup_field (expr.get_field_name ().as_string (),
     700              :                                        nullptr, &field_index);
     701         2038 :       rust_assert (ok);
     702              :     }
     703         3550 :   else if (receiver->get_kind () == TyTy::TypeKind::REF)
     704              :     {
     705         3550 :       TyTy::ReferenceType *r = static_cast<TyTy::ReferenceType *> (receiver);
     706         3550 :       TyTy::BaseType *b = r->get_base ();
     707         3550 :       rust_assert (b->get_kind () == TyTy::TypeKind::ADT);
     708              : 
     709         3550 :       TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (b);
     710         3550 :       rust_assert (!adt->is_enum ());
     711         3550 :       rust_assert (adt->number_of_variants () == 1);
     712              : 
     713         3550 :       TyTy::VariantDef *variant = adt->get_variants ().at (0);
     714         3550 :       bool ok = variant->lookup_field (expr.get_field_name ().as_string (),
     715              :                                        nullptr, &field_index);
     716         3550 :       rust_assert (ok);
     717              : 
     718         3550 :       tree indirect = indirect_expression (receiver_ref, expr.get_locus ());
     719         3550 :       receiver_ref = indirect;
     720              :     }
     721              : 
     722         5588 :   translated = Backend::struct_field_expression (receiver_ref, field_index,
     723              :                                                  expr.get_locus ());
     724              : }
     725              : 
     726              : void
     727          114 : CompileExpr::visit (HIR::QualifiedPathInExpression &expr)
     728              : {
     729          114 :   translated = ResolvePathRef::Compile (expr, ctx);
     730          114 : }
     731              : 
     732              : void
     733        42986 : CompileExpr::visit (HIR::PathInExpression &expr)
     734              : {
     735        42986 :   translated = ResolvePathRef::Compile (expr, ctx);
     736        42986 : }
     737              : 
     738              : void
     739          124 : CompileExpr::visit (HIR::LoopExpr &expr)
     740              : {
     741          124 :   TyTy::BaseType *block_tyty = nullptr;
     742          124 :   fncontext fnctx = ctx->peek_fn ();
     743          124 :   if (ctx->const_context_p () && !DECL_DECLARED_CONSTEXPR_P (fnctx.fndecl))
     744              :     {
     745            3 :       rich_location r (line_table, expr.get_locus ());
     746            3 :       rust_error_at (r, ErrorCode::E0658,
     747              :                      "%<loop%> is not allowed in const context");
     748            3 :       return;
     749            3 :     }
     750              : 
     751          121 :   if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
     752              :                                        &block_tyty))
     753              :     {
     754            0 :       rust_error_at (expr.get_locus (), "failed to lookup type of BlockExpr");
     755            0 :       return;
     756              :     }
     757              : 
     758          121 :   tree enclosing_scope = ctx->peek_enclosing_scope ();
     759          121 :   tree block_type = TyTyResolveCompile::compile (ctx, block_tyty);
     760              : 
     761          121 :   bool is_address_taken = false;
     762          121 :   tree ret_var_stmt = NULL_TREE;
     763          121 :   Bvariable *tmp
     764          121 :     = Backend::temporary_variable (fnctx.fndecl, enclosing_scope, block_type,
     765              :                                    NULL, is_address_taken, expr.get_locus (),
     766              :                                    &ret_var_stmt);
     767          121 :   ctx->add_statement (ret_var_stmt);
     768          121 :   ctx->push_loop_context (tmp);
     769              : 
     770          121 :   if (expr.has_loop_label ())
     771              :     {
     772           34 :       HIR::LoopLabel &loop_label = expr.get_loop_label ();
     773           34 :       tree label
     774           34 :         = Backend::label (fnctx.fndecl, loop_label.get_lifetime ().get_name (),
     775              :                           loop_label.get_locus ());
     776           34 :       tree label_decl = Backend::label_definition_statement (label);
     777           34 :       ctx->add_statement (label_decl);
     778           34 :       ctx->insert_label_decl (
     779           68 :         loop_label.get_lifetime ().get_mappings ().get_hirid (), label);
     780              :     }
     781              : 
     782          121 :   tree loop_begin_label
     783          121 :     = Backend::label (fnctx.fndecl, tl::nullopt, expr.get_locus ());
     784          121 :   tree loop_begin_label_decl
     785          121 :     = Backend::label_definition_statement (loop_begin_label);
     786          121 :   ctx->add_statement (loop_begin_label_decl);
     787          121 :   ctx->push_loop_begin_label (loop_begin_label);
     788              : 
     789          121 :   tree code_block
     790          121 :     = CompileBlock::compile (expr.get_loop_block (), ctx, nullptr);
     791          121 :   tree loop_expr = Backend::loop_expression (code_block, expr.get_locus ());
     792          121 :   ctx->add_statement (loop_expr);
     793              : 
     794          121 :   ctx->pop_loop_context ();
     795          121 :   translated = Backend::var_expression (tmp, expr.get_locus ());
     796              : 
     797          121 :   ctx->pop_loop_begin_label ();
     798              : }
     799              : 
     800              : void
     801           82 : CompileExpr::visit (HIR::WhileLoopExpr &expr)
     802              : {
     803           82 :   fncontext fnctx = ctx->peek_fn ();
     804           82 :   if (expr.has_loop_label ())
     805              :     {
     806            2 :       HIR::LoopLabel &loop_label = expr.get_loop_label ();
     807            2 :       tree label
     808            2 :         = Backend::label (fnctx.fndecl, loop_label.get_lifetime ().get_name (),
     809              :                           loop_label.get_locus ());
     810            2 :       tree label_decl = Backend::label_definition_statement (label);
     811            2 :       ctx->add_statement (label_decl);
     812            2 :       ctx->insert_label_decl (
     813            4 :         loop_label.get_lifetime ().get_mappings ().get_hirid (), label);
     814              :     }
     815              : 
     816           82 :   std::vector<Bvariable *> locals;
     817           82 :   location_t start_location = expr.get_loop_block ().get_locus ();
     818           82 :   location_t end_location = expr.get_loop_block ().get_locus (); // FIXME
     819              : 
     820           82 :   tree enclosing_scope = ctx->peek_enclosing_scope ();
     821           82 :   tree loop_block = Backend::block (fnctx.fndecl, enclosing_scope, locals,
     822              :                                     start_location, end_location);
     823           82 :   ctx->push_block (loop_block);
     824              : 
     825           82 :   tree loop_begin_label
     826           82 :     = Backend::label (fnctx.fndecl, tl::nullopt, expr.get_locus ());
     827           82 :   tree loop_begin_label_decl
     828           82 :     = Backend::label_definition_statement (loop_begin_label);
     829           82 :   ctx->add_statement (loop_begin_label_decl);
     830           82 :   ctx->push_loop_begin_label (loop_begin_label);
     831              : 
     832           82 :   HIR::Expr &predicate = expr.get_predicate_expr ();
     833           82 :   TyTy::BaseType *predicate_type = nullptr;
     834           82 :   bool ok
     835           82 :     = ctx->get_tyctx ()->lookup_type (predicate.get_mappings ().get_hirid (),
     836              :                                       &predicate_type);
     837           82 :   rust_assert (ok && predicate_type != nullptr);
     838           82 :   tree condition = CompileExpr::Compile (predicate, ctx);
     839           82 :   if (predicate_type->get_kind () == TyTy::TypeKind::NEVER)
     840              :     {
     841            9 :       ctx->add_statement (condition);
     842            9 :       condition = boolean_true_node;
     843              :     }
     844           82 :   tree exit_condition = fold_build1_loc (expr.get_locus (), TRUTH_NOT_EXPR,
     845              :                                          boolean_type_node, condition);
     846           82 :   tree exit_expr = Backend::exit_expression (exit_condition, expr.get_locus ());
     847           82 :   ctx->add_statement (exit_expr);
     848              : 
     849           82 :   tree code_block_stmt
     850           82 :     = CompileBlock::compile (expr.get_loop_block (), ctx, nullptr);
     851           82 :   rust_assert (TREE_CODE (code_block_stmt) == BIND_EXPR);
     852           82 :   ctx->add_statement (code_block_stmt);
     853              : 
     854           82 :   ctx->pop_loop_begin_label ();
     855           82 :   ctx->pop_block ();
     856              : 
     857           82 :   tree loop_expr = Backend::loop_expression (loop_block, expr.get_locus ());
     858           82 :   ctx->add_statement (loop_expr);
     859           82 :   translated = unit_expression (expr.get_locus ());
     860           82 : }
     861              : 
     862              : void
     863           84 : CompileExpr::visit (HIR::BreakExpr &expr)
     864              : {
     865           84 :   if (expr.has_break_expr () && expr.has_label ())
     866              :     {
     867            2 :       HIR::Lifetime &label = expr.get_label ();
     868            2 :       auto tvar = lookup_temp_var (label.get_mappings ().get_nodeid ());
     869            2 :       tree value = CompileExpr::Compile (expr.get_expr (), ctx);
     870            2 :       tree assign
     871            2 :         = Backend::assignment_statement (tvar->get_tree (label.get_locus ()),
     872              :                                          value, label.get_locus ());
     873            2 :       tree block_label = lookup_label (label.get_mappings ().get_nodeid ());
     874            2 :       tree go_to = Backend::goto_statement (block_label, label.get_locus ());
     875            2 :       ctx->add_statement (assign);
     876            2 :       ctx->add_statement (go_to);
     877            2 :       return;
     878              :     }
     879           82 :   if (expr.has_break_expr ())
     880              :     {
     881           16 :       tree compiled_expr = CompileExpr::Compile (expr.get_expr (), ctx);
     882           16 :       translated = error_mark_node;
     883              : 
     884           16 :       if (!ctx->have_loop_context ())
     885              :         return;
     886              : 
     887           15 :       Bvariable *loop_result_holder = ctx->peek_loop_context ();
     888           15 :       tree result_reference
     889           15 :         = Backend::var_expression (loop_result_holder,
     890           15 :                                    expr.get_expr ().get_locus ());
     891              : 
     892           15 :       tree assignment
     893           15 :         = Backend::assignment_statement (result_reference, compiled_expr,
     894              :                                          expr.get_locus ());
     895           15 :       ctx->add_statement (assignment);
     896              :     }
     897              : 
     898           81 :   if (expr.has_label ())
     899              :     {
     900           18 :       auto &nr_ctx
     901           18 :         = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
     902              : 
     903           18 :       NodeId resolved_node_id;
     904           36 :       if (auto id
     905           18 :           = nr_ctx.lookup (expr.get_label ().get_mappings ().get_nodeid ()))
     906              :         {
     907           18 :           resolved_node_id = *id;
     908              :         }
     909              :       else
     910              :         {
     911            0 :           rust_error_at (
     912            0 :             expr.get_label ().get_locus (),
     913              :             "failed to resolve compiled label for label %s",
     914            0 :             expr.get_label ().get_mappings ().as_string ().c_str ());
     915            0 :           return;
     916              :         }
     917           18 :       tl::optional<HirId> hid
     918           18 :         = ctx->get_mappings ().lookup_node_to_hir (resolved_node_id);
     919           18 :       if (!hid.has_value ())
     920              :         {
     921            0 :           rust_fatal_error (expr.get_locus (), "reverse lookup label failure");
     922              :           return;
     923              :         }
     924           18 :       auto ref = hid.value ();
     925              : 
     926           18 :       tree label = NULL_TREE;
     927           18 :       if (!ctx->lookup_label_decl (ref, &label))
     928              :         {
     929            0 :           rust_error_at (expr.get_label ().get_locus (),
     930              :                          "failed to lookup compiled label");
     931            0 :           return;
     932              :         }
     933              : 
     934           18 :       tree goto_label = Backend::goto_statement (label, expr.get_locus ());
     935           18 :       ctx->add_statement (goto_label);
     936              :     }
     937              :   else
     938              :     {
     939           63 :       tree exit_expr
     940           63 :         = Backend::exit_expression (Backend::boolean_constant_expression (true),
     941              :                                     expr.get_locus ());
     942           63 :       ctx->add_statement (exit_expr);
     943              :     }
     944              : }
     945              : 
     946              : void
     947           13 : CompileExpr::visit (HIR::ContinueExpr &expr)
     948              : {
     949           13 :   translated = error_mark_node;
     950           13 :   if (!ctx->have_loop_context ())
     951            0 :     return;
     952              : 
     953           13 :   tree label = ctx->peek_loop_begin_label ();
     954           13 :   if (expr.has_label ())
     955              :     {
     956            2 :       auto &nr_ctx
     957            2 :         = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
     958              : 
     959            2 :       NodeId resolved_node_id;
     960            4 :       if (auto id
     961            2 :           = nr_ctx.lookup (expr.get_label ().get_mappings ().get_nodeid ()))
     962              :         {
     963            2 :           resolved_node_id = *id;
     964              :         }
     965              :       else
     966              :         {
     967            0 :           rust_error_at (
     968            0 :             expr.get_label ().get_locus (),
     969              :             "failed to resolve compiled label for label %s",
     970            0 :             expr.get_label ().get_mappings ().as_string ().c_str ());
     971            0 :           return;
     972              :         }
     973              : 
     974            2 :       tl::optional<HirId> hid
     975            2 :         = ctx->get_mappings ().lookup_node_to_hir (resolved_node_id);
     976            2 :       if (!hid.has_value ())
     977              :         {
     978            0 :           rust_fatal_error (expr.get_locus (), "reverse lookup label failure");
     979              :           return;
     980              :         }
     981            2 :       auto ref = hid.value ();
     982              : 
     983            2 :       if (!ctx->lookup_label_decl (ref, &label))
     984              :         {
     985            0 :           rust_error_at (expr.get_label ().get_locus (),
     986              :                          "failed to lookup compiled label");
     987            0 :           return;
     988              :         }
     989              :     }
     990              : 
     991           13 :   translated = Backend::goto_statement (label, expr.get_locus ());
     992              : }
     993              : 
     994              : void
     995         1826 : CompileExpr::visit (HIR::BorrowExpr &expr)
     996              : {
     997         1826 :   tree main_expr = CompileExpr::Compile (expr.get_expr (), ctx);
     998         1826 :   if (RS_DST_FLAG_P (TREE_TYPE (main_expr)))
     999              :     {
    1000           79 :       translated = main_expr;
    1001           79 :       return;
    1002              :     }
    1003              : 
    1004         1747 :   TyTy::BaseType *tyty = nullptr;
    1005         1747 :   if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
    1006              :                                        &tyty))
    1007              :     return;
    1008              : 
    1009         1747 :   tree expected_type = TyTyResolveCompile::compile (ctx, tyty);
    1010         1747 :   translated = address_expression (main_expr, expr.get_locus (), expected_type);
    1011              : }
    1012              : 
    1013              : void
    1014         3650 : CompileExpr::visit (HIR::DereferenceExpr &expr)
    1015              : {
    1016         3650 :   TyTy::BaseType *tyty = nullptr;
    1017         3650 :   if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
    1018              :                                        &tyty))
    1019              :     {
    1020            0 :       rust_fatal_error (expr.get_locus (),
    1021              :                         "did not resolve type for this TupleExpr");
    1022           35 :       return;
    1023              :     }
    1024              : 
    1025         3650 :   tree main_expr = CompileExpr::Compile (expr.get_expr (), ctx);
    1026              : 
    1027              :   // this might be an operator overload situation lets check
    1028         3650 :   TyTy::FnType *fntype;
    1029         3650 :   bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload (
    1030         3650 :     expr.get_mappings ().get_hirid (), &fntype);
    1031         3650 :   if (is_op_overload)
    1032              :     {
    1033           49 :       auto lang_item_type = LangItem::Kind::DEREF;
    1034           49 :       tree operator_overload_call
    1035           49 :         = resolve_operator_overload (lang_item_type, expr, main_expr, nullptr,
    1036              :                                      expr.get_expr (), tl::nullopt);
    1037              : 
    1038              :       // rust deref always returns a reference from this overload then we can
    1039              :       // actually do the indirection
    1040           49 :       main_expr = operator_overload_call;
    1041              :     }
    1042              : 
    1043         3650 :   tree expected_type = TyTyResolveCompile::compile (ctx, tyty);
    1044         3650 :   if (RS_DST_FLAG_P (TREE_TYPE (main_expr)) && RS_DST_FLAG_P (expected_type))
    1045              :     {
    1046           35 :       translated = main_expr;
    1047           35 :       return;
    1048              :     }
    1049              : 
    1050         3615 :   translated = indirect_expression (main_expr, expr.get_locus ());
    1051              : }
    1052              : 
    1053              : void
    1054        23701 : CompileExpr::visit (HIR::LiteralExpr &expr)
    1055              : {
    1056        23701 :   TyTy::BaseType *tyty = nullptr;
    1057        23701 :   if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
    1058              :                                        &tyty))
    1059        23701 :     return;
    1060              : 
    1061        23701 :   switch (expr.get_lit_type ())
    1062              :     {
    1063          904 :     case HIR::Literal::BOOL:
    1064          904 :       translated = compile_bool_literal (expr, tyty);
    1065          904 :       return;
    1066              : 
    1067        18886 :     case HIR::Literal::INT:
    1068        18886 :       translated = compile_integer_literal (expr, tyty);
    1069        18886 :       return;
    1070              : 
    1071          989 :     case HIR::Literal::FLOAT:
    1072          989 :       translated = compile_float_literal (expr, tyty);
    1073          989 :       return;
    1074              : 
    1075          183 :     case HIR::Literal::CHAR:
    1076          183 :       translated = compile_char_literal (expr, tyty);
    1077          183 :       return;
    1078              : 
    1079          408 :     case HIR::Literal::BYTE:
    1080          408 :       translated = compile_byte_literal (expr, tyty);
    1081          408 :       return;
    1082              : 
    1083         2296 :     case HIR::Literal::STRING:
    1084         2296 :       translated = compile_string_literal (expr, tyty);
    1085         2296 :       return;
    1086              : 
    1087           35 :     case HIR::Literal::BYTE_STRING:
    1088           35 :       translated = compile_byte_string_literal (expr, tyty);
    1089           35 :       return;
    1090              :     }
    1091              : }
    1092              : 
    1093              : void
    1094         2431 : CompileExpr::visit (HIR::AssignmentExpr &expr)
    1095              : {
    1096         2431 :   auto lvalue = CompileExpr::Compile (expr.get_lhs (), ctx);
    1097         2431 :   auto rvalue = CompileExpr::Compile (expr.get_rhs (), ctx);
    1098              : 
    1099              :   // assignments are coercion sites so lets convert the rvalue if necessary
    1100         2431 :   TyTy::BaseType *expected = nullptr;
    1101         2431 :   TyTy::BaseType *actual = nullptr;
    1102              : 
    1103         2431 :   bool ok;
    1104         2431 :   ok = ctx->get_tyctx ()->lookup_type (
    1105         2431 :     expr.get_lhs ().get_mappings ().get_hirid (), &expected);
    1106         2431 :   rust_assert (ok);
    1107              : 
    1108         2431 :   ok = ctx->get_tyctx ()->lookup_type (
    1109         2431 :     expr.get_rhs ().get_mappings ().get_hirid (), &actual);
    1110         2431 :   rust_assert (ok);
    1111              : 
    1112         2431 :   rvalue = coercion_site (expr.get_mappings ().get_hirid (), rvalue, actual,
    1113         2431 :                           expected, expr.get_lhs ().get_locus (),
    1114         2431 :                           expr.get_rhs ().get_locus ());
    1115              : 
    1116              :   // rust_debug_loc (expr.get_locus (), "XXXXXX assignment");
    1117              :   // debug_tree (rvalue);
    1118              :   // debug_tree (lvalue);
    1119              : 
    1120         2431 :   tree assignment
    1121         2431 :     = Backend::assignment_statement (lvalue, rvalue, expr.get_locus ());
    1122              : 
    1123         2431 :   ctx->add_statement (assignment);
    1124         2431 :   translated = unit_expression (expr.get_locus ());
    1125         2431 : }
    1126              : 
    1127              : // Helper for CompileExpr::visit (HIR::MatchExpr).
    1128              : // Check that the scrutinee of EXPR is a valid kind of expression to match on.
    1129              : // Return the TypeKind of the scrutinee if it is valid, or TyTy::TypeKind::ERROR
    1130              : // if not.
    1131              : static TyTy::TypeKind
    1132          870 : check_match_scrutinee (HIR::MatchExpr &expr, Context *ctx)
    1133              : {
    1134          870 :   TyTy::BaseType *scrutinee_expr_tyty = nullptr;
    1135          870 :   if (!ctx->get_tyctx ()->lookup_type (
    1136          870 :         expr.get_scrutinee_expr ().get_mappings ().get_hirid (),
    1137              :         &scrutinee_expr_tyty))
    1138              :     {
    1139              :       return TyTy::TypeKind::ERROR;
    1140              :     }
    1141              : 
    1142          870 :   TyTy::TypeKind scrutinee_kind = scrutinee_expr_tyty->get_kind ();
    1143              : 
    1144          870 :   if (scrutinee_kind == TyTy::TypeKind::FLOAT)
    1145              :     {
    1146              :       // FIXME: CASE_LABEL_EXPR does not support floating point types.
    1147              :       // Find another way to compile these.
    1148            2 :       rust_sorry_at (expr.get_locus (),
    1149              :                      "match on floating-point types is not yet supported");
    1150              :     }
    1151              : 
    1152          870 :   TyTy::BaseType *expr_tyty = nullptr;
    1153          870 :   if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
    1154              :                                        &expr_tyty))
    1155              :     {
    1156              :       return TyTy::TypeKind::ERROR;
    1157              :     }
    1158              : 
    1159              :   return scrutinee_kind;
    1160              : }
    1161              : 
    1162              : void
    1163          870 : CompileExpr::visit (HIR::MatchExpr &expr)
    1164              : {
    1165              :   // https://gcc.gnu.org/onlinedocs/gccint/Basic-Statements.html#Basic-Statements
    1166              :   // TODO
    1167              :   // SWITCH_ALL_CASES_P is true if the switch includes a default label or the
    1168              :   // case label ranges cover all possible values of the condition expression
    1169              : 
    1170          870 :   TyTy::TypeKind scrutinee_kind = check_match_scrutinee (expr, ctx);
    1171          870 :   if (scrutinee_kind == TyTy::TypeKind::ERROR)
    1172              :     {
    1173            0 :       translated = error_mark_node;
    1174            4 :       return;
    1175              :     }
    1176              : 
    1177          870 :   TyTy::BaseType *expr_tyty = nullptr;
    1178          870 :   if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
    1179              :                                        &expr_tyty))
    1180              :     {
    1181            0 :       translated = error_mark_node;
    1182            0 :       return;
    1183              :     }
    1184              : 
    1185              :   // if the result of this expression is meant to be never type then we can
    1186              :   // optimise this away but there is the case where match arms resolve to !
    1187              :   // because of return statements we need to special case this
    1188          870 :   if (!expr.has_match_arms () && expr_tyty->is<TyTy::NeverType> ())
    1189              :     {
    1190            4 :       translated = unit_expression (expr.get_locus ());
    1191            4 :       return;
    1192              :     }
    1193              : 
    1194          866 :   fncontext fnctx = ctx->peek_fn ();
    1195          866 :   Bvariable *tmp = NULL;
    1196          866 :   tree enclosing_scope = ctx->peek_enclosing_scope ();
    1197          866 :   tree block_type = TyTyResolveCompile::compile (ctx, expr_tyty);
    1198              : 
    1199          866 :   bool is_address_taken = false;
    1200          866 :   tree ret_var_stmt = nullptr;
    1201          866 :   tmp = Backend::temporary_variable (fnctx.fndecl, enclosing_scope, block_type,
    1202              :                                      NULL, is_address_taken, expr.get_locus (),
    1203              :                                      &ret_var_stmt);
    1204          866 :   ctx->add_statement (ret_var_stmt);
    1205              : 
    1206              :   // lets compile the scrutinee expression
    1207          866 :   tree match_scrutinee_rval
    1208          866 :     = CompileExpr::Compile (expr.get_scrutinee_expr (), ctx);
    1209              : 
    1210          866 :   Bvariable *match_scrutinee_tmp_var
    1211          866 :     = Backend::temporary_variable (fnctx.fndecl, enclosing_scope,
    1212          866 :                                    TREE_TYPE (match_scrutinee_rval), NULL,
    1213              :                                    is_address_taken, expr.get_locus (),
    1214              :                                    &ret_var_stmt);
    1215          866 :   ctx->add_statement (ret_var_stmt);
    1216              : 
    1217          866 :   tree match_scrutinee_expr = match_scrutinee_tmp_var->get_tree (
    1218          866 :     expr.get_scrutinee_expr ().get_locus ());
    1219              : 
    1220          866 :   tree assignment
    1221          866 :     = Backend::assignment_statement (match_scrutinee_expr, match_scrutinee_rval,
    1222              :                                      expr.get_locus ());
    1223          866 :   ctx->add_statement (assignment);
    1224              : 
    1225              :   // setup the end label so the cases can exit properly
    1226          866 :   tree fndecl = fnctx.fndecl;
    1227          866 :   location_t end_label_locus = expr.get_locus (); // FIXME
    1228              :   // tl::nullopt creates an artificial label
    1229          866 :   tree end_label = Backend::label (fndecl, tl::nullopt, end_label_locus);
    1230          866 :   tree end_label_decl_statement
    1231          866 :     = Backend::label_definition_statement (end_label);
    1232              : 
    1233         2927 :   for (auto &kase : expr.get_match_cases ())
    1234              :     {
    1235              :       // for now lets just get single pattern's working
    1236         2061 :       HIR::MatchArm &kase_arm = kase.get_arm ();
    1237         2061 :       rust_assert (kase_arm.get_pattern () != nullptr);
    1238              : 
    1239         2061 :       auto &kase_pattern = kase_arm.get_pattern ();
    1240              :       // setup the match-arm-body-block
    1241         2061 :       location_t start_location = UNKNOWN_LOCATION; // FIXME
    1242         2061 :       location_t end_location = UNKNOWN_LOCATION;   // FIXME
    1243         2061 :       tree arm_body_block = Backend::block (fndecl, enclosing_scope, {},
    1244              :                                             start_location, end_location);
    1245              : 
    1246         2061 :       ctx->push_block (arm_body_block);
    1247              : 
    1248              :       // setup the bindings for the block
    1249         2061 :       CompilePatternBindings::Compile (*kase_pattern, match_scrutinee_expr,
    1250              :                                        ctx);
    1251              : 
    1252              :       // compile the expr and setup the assignment if required when tmp !=
    1253              :       // NULL
    1254         2061 :       location_t arm_locus = kase_arm.get_locus ();
    1255         2061 :       tree kase_expr_tree = CompileExpr::Compile (kase.get_expr (), ctx);
    1256         2061 :       tree result_reference = Backend::var_expression (tmp, arm_locus);
    1257              : 
    1258         2061 :       TyTy::BaseType *actual = nullptr;
    1259         2061 :       bool ok = ctx->get_tyctx ()->lookup_type (
    1260         2061 :         kase.get_expr ().get_mappings ().get_hirid (), &actual);
    1261         2061 :       rust_assert (ok);
    1262              : 
    1263         2061 :       tree coerced_result
    1264         2061 :         = coercion_site (kase.get_expr ().get_mappings ().get_hirid (),
    1265              :                          kase_expr_tree, actual, expr_tyty, expr.get_locus (),
    1266              :                          arm_locus);
    1267              : 
    1268         2061 :       tree assignment
    1269         2061 :         = Backend::assignment_statement (result_reference, coerced_result,
    1270              :                                          arm_locus);
    1271         2061 :       ctx->add_statement (assignment);
    1272              : 
    1273              :       // go to end label
    1274         2061 :       tree goto_end_label
    1275         2061 :         = build1_loc (arm_locus, GOTO_EXPR, void_type_node, end_label);
    1276         2061 :       ctx->add_statement (goto_end_label);
    1277              : 
    1278         2061 :       ctx->pop_block ();
    1279              : 
    1280         2061 :       tree check_expr
    1281         2061 :         = CompilePatternCheckExpr::Compile (*kase_pattern, match_scrutinee_expr,
    1282              :                                             ctx);
    1283              : 
    1284         2061 :       tree check_stmt
    1285         2061 :         = Backend::if_statement (NULL_TREE, check_expr, arm_body_block,
    1286         2061 :                                  NULL_TREE, kase_pattern->get_locus ());
    1287              : 
    1288         2061 :       ctx->add_statement (check_stmt);
    1289              :     }
    1290              : 
    1291              :   // setup the switch expression
    1292          866 :   ctx->add_statement (end_label_decl_statement);
    1293              : 
    1294          866 :   translated = Backend::var_expression (tmp, expr.get_locus ());
    1295              : }
    1296              : 
    1297              : void
    1298        12269 : CompileExpr::visit (HIR::CallExpr &expr)
    1299              : {
    1300        12269 :   TyTy::BaseType *tyty = nullptr;
    1301        12269 :   if (!ctx->get_tyctx ()->lookup_type (
    1302        12269 :         expr.get_fnexpr ().get_mappings ().get_hirid (), &tyty))
    1303              :     {
    1304            0 :       rust_error_at (expr.get_locus (), "unknown type");
    1305         1809 :       return;
    1306              :     }
    1307              : 
    1308              :   // must be a tuple constructor
    1309        12269 :   bool is_adt_ctor = tyty->get_kind () == TyTy::TypeKind::ADT;
    1310        12269 :   if (is_adt_ctor)
    1311              :     {
    1312         1747 :       rust_assert (tyty->get_kind () == TyTy::TypeKind::ADT);
    1313         1747 :       TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (tyty);
    1314         1747 :       tree compiled_adt_type = TyTyResolveCompile::compile (ctx, tyty);
    1315              : 
    1316              :       // what variant is it?
    1317         1747 :       int union_disriminator = -1;
    1318         1747 :       TyTy::VariantDef *variant = nullptr;
    1319         1747 :       if (!adt->is_enum ())
    1320              :         {
    1321          923 :           rust_assert (adt->number_of_variants () == 1);
    1322          923 :           variant = adt->get_variants ().at (0);
    1323              :         }
    1324              :       else
    1325              :         {
    1326          824 :           HirId variant_id;
    1327          824 :           bool ok = ctx->get_tyctx ()->lookup_variant_definition (
    1328          824 :             expr.get_fnexpr ().get_mappings ().get_hirid (), &variant_id);
    1329          824 :           rust_assert (ok);
    1330              : 
    1331          824 :           ok = adt->lookup_variant_by_id (variant_id, &variant,
    1332              :                                           &union_disriminator);
    1333          824 :           rust_assert (ok);
    1334              :         }
    1335              : 
    1336              :       // this assumes all fields are in order from type resolution and if a
    1337              :       // base struct was specified those fields are filed via accessors
    1338         1747 :       std::vector<tree> arguments;
    1339         4027 :       for (size_t i = 0; i < expr.num_params (); i++)
    1340              :         {
    1341         2280 :           auto &argument = expr.get_arguments ().at (i);
    1342         2280 :           auto rvalue = CompileExpr::Compile (*argument, ctx);
    1343              : 
    1344              :           // assignments are coercion sites so lets convert the rvalue if
    1345              :           // necessary
    1346         2280 :           auto respective_field = variant->get_field_at_index (i);
    1347         2280 :           auto expected = respective_field->get_field_type ();
    1348              : 
    1349         2280 :           TyTy::BaseType *actual = nullptr;
    1350         2280 :           bool ok = ctx->get_tyctx ()->lookup_type (
    1351         2280 :             argument->get_mappings ().get_hirid (), &actual);
    1352         2280 :           rust_assert (ok);
    1353              : 
    1354              :           // coerce it if required
    1355         2280 :           location_t lvalue_locus
    1356         2280 :             = ctx->get_mappings ().lookup_location (expected->get_ty_ref ());
    1357         2280 :           location_t rvalue_locus = argument->get_locus ();
    1358         2280 :           rvalue
    1359         2280 :             = coercion_site (argument->get_mappings ().get_hirid (), rvalue,
    1360              :                              actual, expected, lvalue_locus, rvalue_locus);
    1361              : 
    1362              :           // add it to the list
    1363         2280 :           arguments.push_back (rvalue);
    1364              :         }
    1365              : 
    1366         1747 :       if (!adt->is_enum ())
    1367              :         {
    1368          923 :           translated
    1369         1846 :             = Backend::constructor_expression (compiled_adt_type,
    1370          923 :                                                adt->is_enum (), arguments,
    1371              :                                                union_disriminator,
    1372              :                                                expr.get_locus ());
    1373          923 :           return;
    1374              :         }
    1375              : 
    1376          824 :       HIR::Expr &discrim_expr = variant->get_discriminant ();
    1377          824 :       tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx);
    1378          824 :       tree folded_discrim_expr = fold_expr (discrim_expr_node);
    1379          824 :       tree qualifier = folded_discrim_expr;
    1380              : 
    1381          824 :       tree enum_root_files = TYPE_FIELDS (compiled_adt_type);
    1382          824 :       tree payload_root = DECL_CHAIN (enum_root_files);
    1383              : 
    1384          824 :       tree payload
    1385          824 :         = Backend::constructor_expression (TREE_TYPE (payload_root), true,
    1386              :                                            {arguments}, union_disriminator,
    1387              :                                            expr.get_locus ());
    1388              : 
    1389          824 :       std::vector<tree> ctor_arguments = {qualifier, payload};
    1390          824 :       translated = Backend::constructor_expression (compiled_adt_type, false,
    1391              :                                                     ctor_arguments, -1,
    1392              :                                                     expr.get_locus ());
    1393              : 
    1394          824 :       return;
    1395         2571 :     }
    1396              : 
    1397        10522 :   auto get_parameter_tyty_at_index
    1398        10409 :     = [] (const TyTy::BaseType *base, size_t index,
    1399              :           TyTy::BaseType **result) -> bool {
    1400        10409 :     bool is_fn = base->get_kind () == TyTy::TypeKind::FNDEF
    1401        10409 :                  || base->get_kind () == TyTy::TypeKind::FNPTR;
    1402            0 :     rust_assert (is_fn);
    1403              : 
    1404        10409 :     if (base->get_kind () == TyTy::TypeKind::FNPTR)
    1405              :       {
    1406           28 :         const TyTy::FnPtr *fn = static_cast<const TyTy::FnPtr *> (base);
    1407           28 :         *result = fn->get_param_type_at (index);
    1408              : 
    1409           28 :         return true;
    1410              :       }
    1411              : 
    1412        10381 :     const TyTy::FnType *fn = static_cast<const TyTy::FnType *> (base);
    1413        10381 :     auto &param = fn->param_at (index);
    1414        10381 :     *result = param.get_type ();
    1415              : 
    1416        10381 :     return true;
    1417              :   };
    1418              : 
    1419        10522 :   auto fn_address = CompileExpr::Compile (expr.get_fnexpr (), ctx);
    1420        10522 :   if (ctx->const_context_p ())
    1421              :     {
    1422          863 :       if (!FUNCTION_POINTER_TYPE_P (TREE_TYPE (fn_address)))
    1423              :         {
    1424            1 :           rust_error_at (expr.get_locus (),
    1425              :                          "calls in constants are limited to constant "
    1426              :                          "functions, tuple structs and tuple variants");
    1427            1 :           return;
    1428              :         }
    1429              : 
    1430          862 :       if (TREE_CODE (fn_address) == ADDR_EXPR)
    1431              :         {
    1432          862 :           tree fndecl = TREE_OPERAND (fn_address, 0);
    1433          862 :           if (!DECL_DECLARED_CONSTEXPR_P (fndecl))
    1434              :             {
    1435            1 :               rust_error_at (expr.get_locus (),
    1436              :                              "calls in constants are limited to constant "
    1437              :                              "functions, tuple structs and tuple variants");
    1438              :               return;
    1439              :             }
    1440              :         }
    1441              :     }
    1442              : 
    1443              :   // is this a closure call?
    1444        10520 :   bool possible_trait_call
    1445        10520 :     = generate_possible_fn_trait_call (expr, fn_address, &translated);
    1446        10520 :   if (possible_trait_call)
    1447              :     return;
    1448              : 
    1449        10460 :   bool is_variadic = false;
    1450        10460 :   size_t required_num_args = expr.get_arguments ().size ();
    1451              : 
    1452        10460 :   if (tyty->get_kind () == TyTy::TypeKind::FNDEF)
    1453              :     {
    1454        10432 :       const TyTy::FnType *fn = static_cast<const TyTy::FnType *> (tyty);
    1455        10432 :       required_num_args = fn->num_params ();
    1456        10432 :       is_variadic = fn->is_variadic ();
    1457              :     }
    1458           28 :   else if (tyty->get_kind () == TyTy::TypeKind::FNPTR)
    1459              :     {
    1460           28 :       const TyTy::FnPtr *fn = static_cast<const TyTy::FnPtr *> (tyty);
    1461           28 :       required_num_args = fn->num_params ();
    1462              :     }
    1463              : 
    1464        10460 :   std::vector<tree> args;
    1465        21646 :   for (size_t i = 0; i < expr.get_arguments ().size (); i++)
    1466              :     {
    1467        11186 :       auto &argument = expr.get_arguments ().at (i);
    1468        11186 :       auto rvalue = CompileExpr::Compile (*argument, ctx);
    1469              : 
    1470        11186 :       if (is_variadic && i >= required_num_args)
    1471              :         {
    1472          777 :           args.push_back (rvalue);
    1473          777 :           continue;
    1474              :         }
    1475              : 
    1476              :       // assignments are coercion sites so lets convert the rvalue if
    1477              :       // necessary
    1478        10409 :       bool ok;
    1479        10409 :       TyTy::BaseType *expected = nullptr;
    1480        10409 :       ok = get_parameter_tyty_at_index (tyty, i, &expected);
    1481        10409 :       rust_assert (ok);
    1482              : 
    1483        10409 :       TyTy::BaseType *actual = nullptr;
    1484        10409 :       ok = ctx->get_tyctx ()->lookup_type (
    1485        10409 :         argument->get_mappings ().get_hirid (), &actual);
    1486        10409 :       rust_assert (ok);
    1487              : 
    1488              :       // coerce it if required
    1489        10409 :       location_t lvalue_locus
    1490        10409 :         = ctx->get_mappings ().lookup_location (expected->get_ty_ref ());
    1491        10409 :       location_t rvalue_locus = argument->get_locus ();
    1492        10409 :       rvalue = coercion_site (argument->get_mappings ().get_hirid (), rvalue,
    1493              :                               actual, expected, lvalue_locus, rvalue_locus);
    1494              : 
    1495              :       // add it to the list
    1496        10409 :       args.push_back (rvalue);
    1497              :     }
    1498              : 
    1499              :   // must be a regular call to a function
    1500        10460 :   translated
    1501        10460 :     = Backend::call_expression (fn_address, args, nullptr, expr.get_locus ());
    1502        10460 : }
    1503              : 
    1504              : void
    1505         2508 : CompileExpr::visit (HIR::MethodCallExpr &expr)
    1506              : {
    1507              :   // method receiver
    1508         2508 :   tree self = CompileExpr::Compile (expr.get_receiver (), ctx);
    1509              : 
    1510              :   // lookup the expected function type
    1511         2508 :   TyTy::BaseType *lookup_fntype = nullptr;
    1512         2508 :   bool ok = ctx->get_tyctx ()->lookup_type (
    1513         2508 :     expr.get_method_name ().get_mappings ().get_hirid (), &lookup_fntype);
    1514         2508 :   rust_assert (ok);
    1515         2508 :   rust_assert (lookup_fntype->get_kind () == TyTy::TypeKind::FNDEF);
    1516         2508 :   TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup_fntype);
    1517              : 
    1518         2508 :   TyTy::BaseType *receiver = nullptr;
    1519         2508 :   ok = ctx->get_tyctx ()->lookup_type (
    1520         2508 :     expr.get_receiver ().get_mappings ().get_hirid (), &receiver);
    1521         2508 :   rust_assert (ok);
    1522              : 
    1523         2508 :   bool is_dyn_dispatch
    1524         2508 :     = receiver->get_root ()->get_kind () == TyTy::TypeKind::DYNAMIC;
    1525         2508 :   bool is_generic_receiver = receiver->get_kind () == TyTy::TypeKind::PARAM;
    1526         2508 :   if (is_generic_receiver)
    1527              :     {
    1528          193 :       TyTy::ParamType *p = static_cast<TyTy::ParamType *> (receiver);
    1529          193 :       receiver = p->resolve ();
    1530              :     }
    1531              : 
    1532         2508 :   tree fn_expr = error_mark_node;
    1533         2508 :   if (is_dyn_dispatch)
    1534              :     {
    1535          173 :       const TyTy::DynamicObjectType *dyn
    1536          173 :         = static_cast<const TyTy::DynamicObjectType *> (receiver->get_root ());
    1537          173 :       fn_expr
    1538          173 :         = get_fn_addr_from_dyn (dyn, receiver, fntype, self, expr.get_locus ());
    1539          173 :       self = get_receiver_from_dyn (dyn, receiver, fntype, self,
    1540              :                                     expr.get_locus ());
    1541              :     }
    1542              :   else
    1543              :     // lookup compiled functions since it may have already been compiled
    1544         2335 :     fn_expr = resolve_method_address (fntype, receiver, expr.get_locus ());
    1545              : 
    1546              :   // lookup the autoderef mappings
    1547         2508 :   HirId autoderef_mappings_id
    1548         2508 :     = expr.get_receiver ().get_mappings ().get_hirid ();
    1549         2508 :   std::vector<Resolver::Adjustment> *adjustments = nullptr;
    1550         2508 :   ok = ctx->get_tyctx ()->lookup_autoderef_mappings (autoderef_mappings_id,
    1551              :                                                      &adjustments);
    1552         2508 :   rust_assert (ok);
    1553              : 
    1554              :   // apply adjustments for the fn call
    1555         2508 :   self = resolve_adjustements (*adjustments, self,
    1556         2508 :                                expr.get_receiver ().get_locus ());
    1557              : 
    1558         2508 :   std::vector<tree> args;
    1559         2508 :   args.push_back (self); // adjusted self
    1560              : 
    1561              :   // normal args
    1562         4169 :   for (size_t i = 0; i < expr.get_arguments ().size (); i++)
    1563              :     {
    1564         1661 :       auto &argument = expr.get_arguments ().at (i);
    1565         1661 :       auto rvalue = CompileExpr::Compile (*argument, ctx);
    1566              : 
    1567              :       // assignments are coercion sites so lets convert the rvalue if
    1568              :       // necessary, offset from the already adjusted implicit self
    1569         1661 :       bool ok;
    1570         1661 :       TyTy::BaseType *expected = fntype->param_at (i + 1).get_type ();
    1571              : 
    1572         1661 :       TyTy::BaseType *actual = nullptr;
    1573         1661 :       ok = ctx->get_tyctx ()->lookup_type (
    1574         1661 :         argument->get_mappings ().get_hirid (), &actual);
    1575         1661 :       rust_assert (ok);
    1576              : 
    1577              :       // coerce it if required
    1578         1661 :       location_t lvalue_locus
    1579         1661 :         = ctx->get_mappings ().lookup_location (expected->get_ty_ref ());
    1580         1661 :       location_t rvalue_locus = argument->get_locus ();
    1581         1661 :       rvalue = coercion_site (argument->get_mappings ().get_hirid (), rvalue,
    1582              :                               actual, expected, lvalue_locus, rvalue_locus);
    1583              : 
    1584              :       // add it to the list
    1585         1661 :       args.push_back (rvalue);
    1586              :     }
    1587              : 
    1588         2508 :   translated
    1589         2508 :     = Backend::call_expression (fn_expr, args, nullptr, expr.get_locus ());
    1590         2508 : }
    1591              : 
    1592              : tree
    1593          173 : CompileExpr::get_fn_addr_from_dyn (const TyTy::DynamicObjectType *dyn,
    1594              :                                    TyTy::BaseType *receiver,
    1595              :                                    TyTy::FnType *fntype, tree receiver_ref,
    1596              :                                    location_t expr_locus)
    1597              : {
    1598          173 :   size_t offs = 0;
    1599          173 :   const Resolver::TraitItemReference *ref = nullptr;
    1600          231 :   for (auto &bound : dyn->get_object_items ())
    1601              :     {
    1602          231 :       const Resolver::TraitItemReference *item = bound.first;
    1603          231 :       auto t = item->get_tyty ();
    1604          231 :       rust_assert (t->get_kind () == TyTy::TypeKind::FNDEF);
    1605          231 :       auto ft = static_cast<TyTy::FnType *> (t);
    1606              : 
    1607          404 :       if (ft->get_id () == fntype->get_id ())
    1608              :         {
    1609              :           ref = item;
    1610              :           break;
    1611              :         }
    1612           58 :       offs++;
    1613          173 :     }
    1614              : 
    1615          173 :   if (ref == nullptr)
    1616            0 :     return error_mark_node;
    1617              : 
    1618              :   // cast it to the correct fntype
    1619          173 :   tree expected_fntype = TyTyResolveCompile::compile (ctx, fntype, true);
    1620          173 :   tree idx = build_int_cst (size_type_node, offs);
    1621              : 
    1622          173 :   tree vtable_ptr
    1623          173 :     = Backend::struct_field_expression (receiver_ref, 1, expr_locus);
    1624          173 :   tree vtable_array_access
    1625          173 :     = build4_loc (expr_locus, ARRAY_REF, TREE_TYPE (TREE_TYPE (vtable_ptr)),
    1626              :                   vtable_ptr, idx, NULL_TREE, NULL_TREE);
    1627              : 
    1628          173 :   tree vcall = build3_loc (expr_locus, OBJ_TYPE_REF, expected_fntype,
    1629              :                            vtable_array_access, receiver_ref, idx);
    1630              : 
    1631          173 :   return vcall;
    1632              : }
    1633              : 
    1634              : tree
    1635          173 : CompileExpr::get_receiver_from_dyn (const TyTy::DynamicObjectType *dyn,
    1636              :                                     TyTy::BaseType *receiver,
    1637              :                                     TyTy::FnType *fntype, tree receiver_ref,
    1638              :                                     location_t expr_locus)
    1639              : {
    1640              :   // access the offs + 1 for the fnptr and offs=0 for the reciever obj
    1641          173 :   return Backend::struct_field_expression (receiver_ref, 0, expr_locus);
    1642              : }
    1643              : 
    1644              : tree
    1645         1146 : CompileExpr::resolve_operator_overload (
    1646              :   LangItem::Kind lang_item_type, HIR::OperatorExprMeta expr, tree lhs, tree rhs,
    1647              :   HIR::Expr &lhs_expr, tl::optional<std::reference_wrapper<HIR::Expr>> rhs_expr,
    1648              :   HIR::PathIdentSegment specified_segment)
    1649              : {
    1650         1146 :   TyTy::FnType *fntype;
    1651         1146 :   bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload (
    1652         1146 :     expr.get_mappings ().get_hirid (), &fntype);
    1653         1146 :   rust_assert (is_op_overload);
    1654              : 
    1655         1146 :   TyTy::BaseType *receiver = nullptr;
    1656         1146 :   bool ok
    1657         1146 :     = ctx->get_tyctx ()->lookup_type (lhs_expr.get_mappings ().get_hirid (),
    1658              :                                       &receiver);
    1659         1146 :   rust_assert (ok);
    1660              : 
    1661         1146 :   bool is_generic_receiver = receiver->get_kind () == TyTy::TypeKind::PARAM;
    1662         1146 :   if (is_generic_receiver)
    1663              :     {
    1664           14 :       TyTy::ParamType *p = static_cast<TyTy::ParamType *> (receiver);
    1665           14 :       receiver = p->resolve ();
    1666              :     }
    1667              : 
    1668              :   // lookup compiled functions since it may have already been compiled
    1669         1146 :   HIR::PathIdentSegment segment_name
    1670         1146 :     = specified_segment.is_error ()
    1671         1452 :         ? HIR::PathIdentSegment (LangItem::ToString (lang_item_type))
    1672         1146 :         : specified_segment;
    1673         1146 :   tree fn_expr = resolve_method_address (fntype, receiver, expr.get_locus ());
    1674              : 
    1675              :   // lookup the autoderef mappings
    1676         1146 :   std::vector<Resolver::Adjustment> *adjustments = nullptr;
    1677         1146 :   ok = ctx->get_tyctx ()->lookup_autoderef_mappings (
    1678         1146 :     expr.get_lvalue_mappings ().get_hirid (), &adjustments);
    1679         1146 :   rust_assert (ok);
    1680              : 
    1681              :   // apply adjustments for the fn call
    1682         1146 :   tree self = resolve_adjustements (*adjustments, lhs, lhs_expr.get_locus ());
    1683              : 
    1684         1146 :   std::vector<tree> args;
    1685         1146 :   args.push_back (self); // adjusted self
    1686         1146 :   if (rhs != nullptr)    // can be null for negation_expr (unary ones)
    1687         1083 :     args.push_back (rhs);
    1688              : 
    1689         1146 :   return Backend::call_expression (fn_expr, args, nullptr, expr.get_locus ());
    1690         1146 : }
    1691              : 
    1692              : tree
    1693          904 : CompileExpr::compile_bool_literal (const HIR::LiteralExpr &expr,
    1694              :                                    const TyTy::BaseType *tyty)
    1695              : {
    1696          904 :   rust_assert (expr.get_lit_type () == HIR::Literal::BOOL);
    1697              : 
    1698          904 :   const auto literal_value = expr.get_literal ();
    1699         1808 :   bool bval = literal_value.as_string ().compare ("true") == 0;
    1700          904 :   return Backend::boolean_constant_expression (bval);
    1701          904 : }
    1702              : 
    1703              : tree
    1704        18886 : CompileExpr::compile_integer_literal (const HIR::LiteralExpr &expr,
    1705              :                                       const TyTy::BaseType *tyty)
    1706              : {
    1707        18886 :   rust_assert (expr.get_lit_type () == HIR::Literal::INT);
    1708        18886 :   const auto &literal_value = expr.get_literal ();
    1709        18886 :   tree type = TyTyResolveCompile::compile (ctx, tyty);
    1710              : 
    1711        18886 :   std::string s = literal_value.as_string ();
    1712        18886 :   s.erase (std::remove (s.begin (), s.end (), '_'), s.end ());
    1713              : 
    1714        18886 :   int base = 0;
    1715        18886 :   mpz_t ival;
    1716        18886 :   if (mpz_init_set_str (ival, s.c_str (), base) != 0)
    1717              :     {
    1718            0 :       rust_error_at (expr.get_locus (), "failed to load number literal");
    1719            0 :       return error_mark_node;
    1720              :     }
    1721        18886 :   if (expr.is_negative ())
    1722          658 :     mpz_neg (ival, ival);
    1723              : 
    1724        18886 :   mpz_t type_min, type_max;
    1725        18886 :   mpz_init (type_min);
    1726        18886 :   mpz_init (type_max);
    1727        18886 :   get_type_static_bounds (type, type_min, type_max);
    1728              : 
    1729        18886 :   if (mpz_cmp (ival, type_min) < 0 || mpz_cmp (ival, type_max) > 0)
    1730              :     {
    1731            2 :       rust_error_at (expr.get_locus (),
    1732              :                      "integer overflows the respective type %qs",
    1733            2 :                      tyty->get_name ().c_str ());
    1734            2 :       mpz_clear (type_min);
    1735            2 :       mpz_clear (type_max);
    1736            2 :       mpz_clear (ival);
    1737            2 :       return error_mark_node;
    1738              :     }
    1739              : 
    1740        18884 :   tree result = wide_int_to_tree (type, wi::from_mpz (type, ival, true));
    1741        18884 :   mpz_clear (type_min);
    1742        18884 :   mpz_clear (type_max);
    1743        18884 :   mpz_clear (ival);
    1744              : 
    1745        18884 :   return result;
    1746        18886 : }
    1747              : 
    1748              : tree
    1749          989 : CompileExpr::compile_float_literal (const HIR::LiteralExpr &expr,
    1750              :                                     const TyTy::BaseType *tyty)
    1751              : {
    1752          989 :   rust_assert (expr.get_lit_type () == HIR::Literal::FLOAT);
    1753          989 :   const auto literal_value = expr.get_literal ();
    1754              : 
    1755          989 :   tree type = TyTyResolveCompile::compile (ctx, tyty);
    1756              : 
    1757          989 :   mpfr_t fval;
    1758         2967 :   if (mpfr_init_set_str (fval, literal_value.as_string ().c_str (), 10,
    1759              :                          MPFR_RNDN)
    1760          989 :       != 0)
    1761              :     {
    1762            0 :       rust_error_at (expr.get_locus (), "bad number in literal");
    1763            0 :       return error_mark_node;
    1764              :     }
    1765          989 :   if (expr.is_negative ())
    1766            6 :     mpfr_neg (fval, fval, MPFR_RNDN);
    1767              : 
    1768              :   // taken from:
    1769              :   // see go/gofrontend/expressions.cc:check_float_type
    1770          989 :   bool real_value_overflow;
    1771              : 
    1772          989 :   if (mpfr_regular_p (fval) != 0)
    1773              :     {
    1774          882 :       mpfr_exp_t exp = mpfr_get_exp (fval);
    1775          882 :       mpfr_exp_t min_exp;
    1776          882 :       mpfr_exp_t max_exp;
    1777              : 
    1778              :       /*
    1779              :        * By convention, the radix point of the significand is just before the
    1780              :        * first digit (which is always 1 due to normalization), like in the C
    1781              :        * language, but unlike in IEEE 754 (thus, for a given number, the
    1782              :        * exponent values in MPFR and in IEEE 754 differ by 1).
    1783              :        */
    1784          882 :       switch (TYPE_PRECISION (type))
    1785              :         {
    1786              :         case 32:
    1787              :           min_exp = -128 + 1;
    1788              :           max_exp = 127 + 1;
    1789              :           break;
    1790          312 :         case 64:
    1791          312 :           min_exp = -1024 + 1;
    1792          312 :           max_exp = 1023 + 1;
    1793          312 :           break;
    1794            0 :         default:
    1795            0 :           rust_error_at (expr.get_locus (),
    1796              :                          "precision of type %<%s%> not supported",
    1797            0 :                          tyty->get_name ().c_str ());
    1798            0 :           return error_mark_node;
    1799              :         }
    1800          882 :       real_value_overflow = exp < min_exp || exp > max_exp;
    1801              :     }
    1802              :   else
    1803              :     {
    1804              :       real_value_overflow = false;
    1805              :     }
    1806              : 
    1807          989 :   REAL_VALUE_TYPE r1;
    1808          989 :   real_from_mpfr (&r1, fval, type, GMP_RNDN);
    1809          989 :   REAL_VALUE_TYPE r2;
    1810          989 :   real_convert (&r2, TYPE_MODE (type), &r1);
    1811              : 
    1812          989 :   tree real_value = build_real (type, r2);
    1813          989 :   if (TREE_OVERFLOW (real_value) || real_value_overflow)
    1814              :     {
    1815            1 :       rust_error_at (expr.get_locus (),
    1816              :                      "decimal overflows the respective type %qs",
    1817            1 :                      tyty->get_name ().c_str ());
    1818            1 :       return error_mark_node;
    1819              :     }
    1820              : 
    1821              :   return real_value;
    1822          989 : }
    1823              : 
    1824              : tree
    1825          183 : CompileExpr::compile_char_literal (const HIR::LiteralExpr &expr,
    1826              :                                    const TyTy::BaseType *tyty)
    1827              : {
    1828          183 :   rust_assert (expr.get_lit_type () == HIR::Literal::CHAR);
    1829          183 :   const auto literal_value = expr.get_literal ();
    1830              : 
    1831              :   // FIXME needs wchar_t
    1832          366 :   char c = literal_value.as_string ().c_str ()[0];
    1833          183 :   return Backend::wchar_constant_expression (c);
    1834          183 : }
    1835              : 
    1836              : tree
    1837          408 : CompileExpr::compile_byte_literal (const HIR::LiteralExpr &expr,
    1838              :                                    const TyTy::BaseType *tyty)
    1839              : {
    1840          408 :   rust_assert (expr.get_lit_type () == HIR::Literal::BYTE);
    1841          408 :   const auto literal_value = expr.get_literal ();
    1842              : 
    1843          408 :   tree type = TyTyResolveCompile::compile (ctx, tyty);
    1844          816 :   char c = literal_value.as_string ().c_str ()[0];
    1845          408 :   return build_int_cst (type, c);
    1846          408 : }
    1847              : 
    1848              : tree
    1849         2296 : CompileExpr::compile_string_literal (const HIR::LiteralExpr &expr,
    1850              :                                      const TyTy::BaseType *tyty)
    1851              : {
    1852         2296 :   tree fat_pointer = TyTyResolveCompile::compile (ctx, tyty);
    1853              : 
    1854         2296 :   rust_assert (expr.get_lit_type () == HIR::Literal::STRING);
    1855         2296 :   const auto literal_value = expr.get_literal ();
    1856              : 
    1857         4592 :   auto base = Backend::string_constant_expression (literal_value.as_string ());
    1858         2296 :   tree data = address_expression (base, expr.get_locus ());
    1859              : 
    1860         2296 :   TyTy::BaseType *usize = nullptr;
    1861         2296 :   bool ok = ctx->get_tyctx ()->lookup_builtin ("usize", &usize);
    1862         2296 :   rust_assert (ok);
    1863         2296 :   tree type = TyTyResolveCompile::compile (ctx, usize);
    1864              : 
    1865         4592 :   tree size = build_int_cstu (type, literal_value.as_string ().size ());
    1866              : 
    1867         2296 :   return Backend::constructor_expression (fat_pointer, false, {data, size}, -1,
    1868         2296 :                                           expr.get_locus ());
    1869         2296 : }
    1870              : 
    1871              : tree
    1872           35 : CompileExpr::compile_byte_string_literal (const HIR::LiteralExpr &expr,
    1873              :                                           const TyTy::BaseType *tyty)
    1874              : {
    1875           35 :   rust_assert (expr.get_lit_type () == HIR::Literal::BYTE_STRING);
    1876              : 
    1877              :   // the type here is &[ty; capacity]
    1878           35 :   rust_assert (tyty->get_kind () == TyTy::TypeKind::REF);
    1879           35 :   const auto ref_tyty = static_cast<const TyTy::ReferenceType *> (tyty);
    1880           35 :   auto base_tyty = ref_tyty->get_base ();
    1881           35 :   rust_assert (base_tyty->get_kind () == TyTy::TypeKind::ARRAY);
    1882           35 :   auto array_tyty = static_cast<TyTy::ArrayType *> (base_tyty);
    1883              : 
    1884           35 :   std::string value_str = expr.get_literal ().as_string ();
    1885           35 :   std::vector<tree> vals;
    1886           35 :   std::vector<unsigned long> indexes;
    1887          273 :   for (size_t i = 0; i < value_str.size (); i++)
    1888              :     {
    1889          238 :       char b = value_str.at (i);
    1890          238 :       tree bb = Backend::char_constant_expression (b);
    1891          238 :       vals.push_back (bb);
    1892          238 :       indexes.push_back (i);
    1893              :     }
    1894              : 
    1895           35 :   tree array_type = TyTyResolveCompile::compile (ctx, array_tyty);
    1896           35 :   tree constructed
    1897           35 :     = Backend::array_constructor_expression (array_type, indexes, vals,
    1898              :                                              expr.get_locus ());
    1899              : 
    1900           35 :   return address_expression (constructed, expr.get_locus ());
    1901           35 : }
    1902              : 
    1903              : tree
    1904         4860 : CompileExpr::type_cast_expression (tree type_to_cast_to, tree expr_tree,
    1905              :                                    location_t location)
    1906              : {
    1907         4860 :   if (type_to_cast_to == error_mark_node || expr_tree == error_mark_node
    1908         9720 :       || TREE_TYPE (expr_tree) == error_mark_node)
    1909              :     return error_mark_node;
    1910              : 
    1911         4860 :   if (Backend::type_size (type_to_cast_to) == 0
    1912         4860 :       || TREE_TYPE (expr_tree) == void_type_node)
    1913              :     {
    1914              :       // Do not convert zero-sized types.
    1915              :       return expr_tree;
    1916              :     }
    1917         4860 :   else if (TREE_CODE (type_to_cast_to) == INTEGER_TYPE)
    1918              :     {
    1919         1292 :       tree cast = convert_to_integer (type_to_cast_to, expr_tree);
    1920              :       // FIXME check for TREE_OVERFLOW?
    1921         1292 :       return cast;
    1922              :     }
    1923         3568 :   else if (TREE_CODE (type_to_cast_to) == REAL_TYPE)
    1924              :     {
    1925            9 :       tree cast = convert_to_real (type_to_cast_to, expr_tree);
    1926              :       // FIXME
    1927              :       // We might need to check that the tree is MAX val and thusly saturate it
    1928              :       // to inf. we can get the bounds and check the value if its >= or <= to
    1929              :       // the min and max bounds
    1930              :       //
    1931              :       // https://github.com/Rust-GCC/gccrs/issues/635
    1932            9 :       return cast;
    1933              :     }
    1934         3559 :   else if (TREE_CODE (type_to_cast_to) == COMPLEX_TYPE)
    1935              :     {
    1936            0 :       return convert_to_complex (type_to_cast_to, expr_tree);
    1937              :     }
    1938         3559 :   else if (TREE_CODE (type_to_cast_to) == POINTER_TYPE
    1939         3559 :            && TREE_CODE (TREE_TYPE (expr_tree)) == INTEGER_TYPE)
    1940              :     {
    1941            7 :       return convert_to_pointer (type_to_cast_to, expr_tree);
    1942              :     }
    1943         3552 :   else if (TREE_CODE (type_to_cast_to) == RECORD_TYPE
    1944         3552 :            || TREE_CODE (type_to_cast_to) == ARRAY_TYPE)
    1945              :     {
    1946         1630 :       return fold_build1_loc (location, VIEW_CONVERT_EXPR, type_to_cast_to,
    1947         1630 :                               expr_tree);
    1948              :     }
    1949         1922 :   else if (TREE_CODE (type_to_cast_to) == POINTER_TYPE
    1950         1922 :            && RS_DST_FLAG (TREE_TYPE (expr_tree)))
    1951              :     {
    1952              :       // returning a raw cast using NOP_EXPR seems to resut in an ICE:
    1953              :       //
    1954              :       // Analyzing compilation unit
    1955              :       // Performing interprocedural optimizations
    1956              :       //  <*free_lang_data> {heap 2644k} <visibility> {heap 2644k}
    1957              :       //  <build_ssa_passes> {heap 2644k} <opt_local_passes> {heap 2644k}during
    1958              :       //  GIMPLE pass: cddce
    1959              :       // In function ‘*T::as_ptr<i32>’:
    1960              :       // rust1: internal compiler error: in propagate_necessity, at
    1961              :       // tree-ssa-dce.cc:984 0x1d5b43e propagate_necessity
    1962              :       //         ../../gccrs/gcc/tree-ssa-dce.cc:984
    1963              :       // 0x1d5e180 perform_tree_ssa_dce
    1964              :       //         ../../gccrs/gcc/tree-ssa-dce.cc:1876
    1965              :       // 0x1d5e2c8 tree_ssa_cd_dce
    1966              :       //         ../../gccrs/gcc/tree-ssa-dce.cc:1920
    1967              :       // 0x1d5e49a execute
    1968              :       //         ../../gccrs/gcc/tree-ssa-dce.cc:1992
    1969              : 
    1970              :       // this is returning the direct raw pointer of the slice an assumes a very
    1971              :       // specific layout
    1972         1650 :       return Backend::struct_field_expression (expr_tree, 0, location);
    1973              :     }
    1974              : 
    1975          272 :   return fold_convert_loc (location, type_to_cast_to, expr_tree);
    1976              : }
    1977              : 
    1978              : void
    1979          395 : CompileExpr::visit (HIR::ArrayExpr &expr)
    1980              : {
    1981          395 :   TyTy::BaseType *tyty = nullptr;
    1982          395 :   if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
    1983              :                                        &tyty))
    1984              :     {
    1985            0 :       rust_fatal_error (expr.get_locus (),
    1986              :                         "did not resolve type for this array expr");
    1987          283 :       return;
    1988              :     }
    1989              : 
    1990          395 :   tree array_type = TyTyResolveCompile::compile (ctx, tyty);
    1991          395 :   if (TREE_CODE (array_type) != ARRAY_TYPE)
    1992              :     {
    1993            0 :       translated = error_mark_node;
    1994            0 :       return;
    1995              :     }
    1996              : 
    1997          395 :   rust_assert (tyty->get_kind () == TyTy::TypeKind::ARRAY);
    1998          395 :   const TyTy::ArrayType &array_tyty
    1999              :     = static_cast<const TyTy::ArrayType &> (*tyty);
    2000              : 
    2001          395 :   HIR::ArrayElems &elements = expr.get_internal_elements ();
    2002          395 :   switch (elements.get_array_expr_type ())
    2003              :     {
    2004          283 :     case HIR::ArrayElems::ArrayExprType::VALUES:
    2005          283 :       {
    2006          283 :         HIR::ArrayElemsValues &elems
    2007              :           = static_cast<HIR::ArrayElemsValues &> (elements);
    2008          283 :         translated
    2009          283 :           = array_value_expr (expr.get_locus (), array_tyty, array_type, elems);
    2010              :       }
    2011          283 :       return;
    2012              : 
    2013          112 :     case HIR::ArrayElems::ArrayExprType::COPIED:
    2014          112 :       HIR::ArrayElemsCopied &elems
    2015              :         = static_cast<HIR::ArrayElemsCopied &> (elements);
    2016          112 :       translated
    2017          112 :         = array_copied_expr (expr.get_locus (), array_tyty, array_type, elems);
    2018              :     }
    2019              : }
    2020              : 
    2021              : tree
    2022          283 : CompileExpr::array_value_expr (location_t expr_locus,
    2023              :                                const TyTy::ArrayType &array_tyty,
    2024              :                                tree array_type, HIR::ArrayElemsValues &elems)
    2025              : {
    2026          283 :   std::vector<unsigned long> indexes;
    2027          283 :   std::vector<tree> constructor;
    2028          283 :   size_t i = 0;
    2029         1742 :   for (auto &elem : elems.get_values ())
    2030              :     {
    2031         1460 :       tree translated_expr = CompileExpr::Compile (*elem, ctx);
    2032         1460 :       if (translated_expr == error_mark_node)
    2033              :         {
    2034            1 :           rich_location r (line_table, expr_locus);
    2035            1 :           r.add_fixit_replace (elem->get_locus (), "not a value");
    2036            1 :           rust_error_at (r, ErrorCode::E0423, "expected value");
    2037            1 :           return error_mark_node;
    2038            1 :         }
    2039              : 
    2040         1459 :       constructor.push_back (translated_expr);
    2041         1459 :       indexes.push_back (i++);
    2042              :     }
    2043              : 
    2044          282 :   return Backend::array_constructor_expression (array_type, indexes,
    2045          282 :                                                 constructor, expr_locus);
    2046          283 : }
    2047              : 
    2048              : tree
    2049          112 : CompileExpr::array_copied_expr (location_t expr_locus,
    2050              :                                 const TyTy::ArrayType &array_tyty,
    2051              :                                 tree array_type, HIR::ArrayElemsCopied &elems)
    2052              : {
    2053              :   //  see gcc/cp/typeck2.cc:1369-1401
    2054          112 :   gcc_assert (TREE_CODE (array_type) == ARRAY_TYPE);
    2055          112 :   tree domain = TYPE_DOMAIN (array_type);
    2056          112 :   if (!domain)
    2057            0 :     return error_mark_node;
    2058              : 
    2059          112 :   if (!TREE_CONSTANT (TYPE_MAX_VALUE (domain)))
    2060              :     {
    2061            0 :       rust_error_at (expr_locus, "non const capacity domain %qT", array_type);
    2062            0 :       return error_mark_node;
    2063              :     }
    2064              : 
    2065          112 :   auto capacity_ty = array_tyty.get_capacity ();
    2066              : 
    2067              :   // Check if capacity is a const type
    2068          112 :   if (capacity_ty->get_kind () != TyTy::TypeKind::CONST)
    2069              :     {
    2070            0 :       rust_error_at (array_tyty.get_locus (),
    2071              :                      "array capacity is not a const type");
    2072            0 :       return error_mark_node;
    2073              :     }
    2074              : 
    2075          112 :   auto *capacity_const = capacity_ty->as_const_type ();
    2076              : 
    2077          112 :   rust_assert (capacity_const->const_kind ()
    2078              :                == TyTy::BaseConstType::ConstKind::Value);
    2079          112 :   auto &capacity_value = *static_cast<TyTy::ConstValueType *> (capacity_const);
    2080          112 :   auto cap_tree = capacity_value.get_value ();
    2081          112 :   if (error_operand_p (cap_tree) || !TREE_CONSTANT (cap_tree))
    2082              :     {
    2083            0 :       rust_error_at (expr_locus, "non const num copies %qT", cap_tree);
    2084            0 :       return error_mark_node;
    2085              :     }
    2086              : 
    2087              :   // get the compiled value
    2088          112 :   tree translated_expr = CompileExpr::Compile (elems.get_elem_to_copy (), ctx);
    2089              : 
    2090          112 :   tree max_domain = TYPE_MAX_VALUE (domain);
    2091          112 :   tree min_domain = TYPE_MIN_VALUE (domain);
    2092              : 
    2093          112 :   auto max = wi::to_offset (max_domain);
    2094          112 :   auto min = wi::to_offset (min_domain);
    2095          112 :   auto precision = TYPE_PRECISION (TREE_TYPE (domain));
    2096          112 :   auto sign = TYPE_SIGN (TREE_TYPE (domain));
    2097          112 :   unsigned HOST_WIDE_INT len
    2098          112 :     = wi::ext (max - min + 1, precision, sign).to_uhwi ();
    2099              : 
    2100              :   // In a const context we must initialize the entire array, which entails
    2101              :   // allocating for each element. If the user wants a huge array, we will OOM
    2102              :   // and die horribly.
    2103          112 :   if (ctx->const_context_p ())
    2104              :     {
    2105            8 :       size_t idx = 0;
    2106              : 
    2107            8 :       std::vector<unsigned long> indexes;
    2108            8 :       std::vector<tree> constructor;
    2109              : 
    2110            8 :       indexes.reserve (len);
    2111            8 :       constructor.reserve (len);
    2112          130 :       for (unsigned HOST_WIDE_INT i = 0; i < len; i++)
    2113              :         {
    2114          122 :           constructor.push_back (translated_expr);
    2115          122 :           indexes.push_back (idx++);
    2116              :         }
    2117              : 
    2118            8 :       return Backend::array_constructor_expression (array_type, indexes,
    2119              :                                                     constructor, expr_locus);
    2120            8 :     }
    2121              : 
    2122              :   else
    2123              :     {
    2124              :       // Create a new block scope in which to initialize the array
    2125          104 :       tree fndecl = NULL_TREE;
    2126          104 :       if (ctx->in_fn ())
    2127          104 :         fndecl = ctx->peek_fn ().fndecl;
    2128              : 
    2129          104 :       std::vector<Bvariable *> locals;
    2130          104 :       tree enclosing_scope = ctx->peek_enclosing_scope ();
    2131          104 :       tree init_block = Backend::block (fndecl, enclosing_scope, locals,
    2132              :                                         expr_locus, expr_locus);
    2133          104 :       ctx->push_block (init_block);
    2134              : 
    2135          104 :       tree tmp;
    2136          104 :       tree stmts
    2137          104 :         = Backend::array_initializer (fndecl, init_block, array_type, cap_tree,
    2138              :                                       translated_expr, &tmp, expr_locus);
    2139          104 :       ctx->add_statement (stmts);
    2140              : 
    2141          104 :       tree block = ctx->pop_block ();
    2142              : 
    2143              :       // The result is a compound expression which creates a temporary array,
    2144              :       // initializes all the elements in a loop, and then yeilds the array.
    2145          104 :       return Backend::compound_expression (block, tmp, expr_locus);
    2146          104 :     }
    2147              : }
    2148              : 
    2149              : tree
    2150        39244 : HIRCompileBase::resolve_adjustements (
    2151              :   std::vector<Resolver::Adjustment> &adjustments, tree expression,
    2152              :   location_t locus)
    2153              : {
    2154        39244 :   tree e = expression;
    2155        41386 :   for (auto &adjustment : adjustments)
    2156              :     {
    2157         2143 :       if (e == error_mark_node)
    2158              :         return error_mark_node;
    2159              : 
    2160         2142 :       switch (adjustment.get_type ())
    2161              :         {
    2162              :         case Resolver::Adjustment::AdjustmentType::ERROR:
    2163              :           return error_mark_node;
    2164              : 
    2165         1649 :         case Resolver::Adjustment::AdjustmentType::IMM_REF:
    2166         1649 :         case Resolver::Adjustment::AdjustmentType::MUT_REF:
    2167         1649 :           {
    2168         1649 :             if (!RS_DST_FLAG (TREE_TYPE (e)))
    2169              :               {
    2170         1460 :                 e = address_expression (e, locus);
    2171              :               }
    2172              :           }
    2173              :           break;
    2174              : 
    2175           56 :         case Resolver::Adjustment::AdjustmentType::DEREF:
    2176           56 :         case Resolver::Adjustment::AdjustmentType::DEREF_MUT:
    2177           56 :           e = resolve_deref_adjustment (adjustment, e, locus);
    2178           56 :           break;
    2179              : 
    2180          248 :         case Resolver::Adjustment::AdjustmentType::INDIRECTION:
    2181          248 :           e = resolve_indirection_adjustment (adjustment, e, locus);
    2182          248 :           break;
    2183              : 
    2184          189 :         case Resolver::Adjustment::AdjustmentType::UNSIZE:
    2185          189 :           e = resolve_unsized_adjustment (adjustment, e, locus);
    2186          189 :           break;
    2187              :         }
    2188              :     }
    2189              : 
    2190              :   return e;
    2191              : }
    2192              : 
    2193              : tree
    2194           56 : HIRCompileBase::resolve_deref_adjustment (Resolver::Adjustment &adjustment,
    2195              :                                           tree expression, location_t locus)
    2196              : {
    2197           56 :   rust_assert (adjustment.is_deref_adjustment ()
    2198              :                || adjustment.is_deref_mut_adjustment ());
    2199           56 :   rust_assert (adjustment.has_operator_overload ());
    2200              : 
    2201           56 :   TyTy::FnType *lookup = adjustment.get_deref_operator_fn ();
    2202           56 :   TyTy::BaseType *receiver = adjustment.get_actual ();
    2203           56 :   tree fn_address = resolve_method_address (lookup, receiver, locus);
    2204              : 
    2205              :   // does it need a reference to call
    2206           56 :   tree adjusted_argument = expression;
    2207           56 :   bool needs_borrow = adjustment.get_deref_adjustment_type ()
    2208           56 :                       != Resolver::Adjustment::AdjustmentType::ERROR;
    2209           56 :   if (needs_borrow)
    2210              :     {
    2211           56 :       adjusted_argument = address_expression (expression, locus);
    2212              :     }
    2213              : 
    2214              :   // make the call
    2215           56 :   return Backend::call_expression (fn_address, {adjusted_argument}, nullptr,
    2216           56 :                                    locus);
    2217              : }
    2218              : 
    2219              : tree
    2220          248 : HIRCompileBase::resolve_indirection_adjustment (
    2221              :   Resolver::Adjustment &adjustment, tree expression, location_t locus)
    2222              : {
    2223          248 :   return indirect_expression (expression, locus);
    2224              : }
    2225              : 
    2226              : tree
    2227          189 : HIRCompileBase::resolve_unsized_adjustment (Resolver::Adjustment &adjustment,
    2228              :                                             tree expression, location_t locus)
    2229              : {
    2230          189 :   bool expect_slice
    2231          189 :     = adjustment.get_expected ()->get_kind () == TyTy::TypeKind::SLICE;
    2232          189 :   bool expect_dyn
    2233          189 :     = adjustment.get_expected ()->get_kind () == TyTy::TypeKind::DYNAMIC;
    2234              : 
    2235              :   // assumes this is an array
    2236          189 :   tree expr_type = TREE_TYPE (expression);
    2237          189 :   if (expect_slice)
    2238              :     {
    2239           65 :       rust_assert (TREE_CODE (expr_type) == ARRAY_TYPE);
    2240           65 :       return resolve_unsized_slice_adjustment (adjustment, expression, locus);
    2241              :     }
    2242              : 
    2243          124 :   rust_assert (expect_dyn);
    2244          124 :   return resolve_unsized_dyn_adjustment (adjustment, expression, locus);
    2245              : }
    2246              : 
    2247              : tree
    2248           65 : HIRCompileBase::resolve_unsized_slice_adjustment (
    2249              :   Resolver::Adjustment &adjustment, tree expression, location_t locus)
    2250              : {
    2251              :   // assumes this is an array
    2252           65 :   tree expr_type = TREE_TYPE (expression);
    2253           65 :   rust_assert (TREE_CODE (expr_type) == ARRAY_TYPE);
    2254              : 
    2255              :   // takes an array and returns a fat-pointer so this becomes a constructor
    2256              :   // expression
    2257           65 :   rust_assert (adjustment.get_expected ()->get_kind ()
    2258              :                == TyTy::TypeKind::SLICE);
    2259           65 :   tree fat_pointer
    2260           65 :     = TyTyResolveCompile::compile (ctx, adjustment.get_expected ());
    2261              : 
    2262              :   // make a constructor for this
    2263           65 :   tree data = address_expression (expression, locus);
    2264              : 
    2265              :   // fetch the size from the domain
    2266           65 :   tree domain = TYPE_DOMAIN (expr_type);
    2267           65 :   unsigned HOST_WIDE_INT array_size
    2268          130 :     = wi::ext (wi::to_offset (TYPE_MAX_VALUE (domain))
    2269          130 :                  - wi::to_offset (TYPE_MIN_VALUE (domain)) + 1,
    2270           65 :                TYPE_PRECISION (TREE_TYPE (domain)),
    2271           65 :                TYPE_SIGN (TREE_TYPE (domain)))
    2272           65 :         .to_uhwi ();
    2273           65 :   tree size = build_int_cstu (size_type_node, array_size);
    2274              : 
    2275           65 :   return Backend::constructor_expression (fat_pointer, false, {data, size}, -1,
    2276           65 :                                           locus);
    2277              : }
    2278              : 
    2279              : tree
    2280          124 : HIRCompileBase::resolve_unsized_dyn_adjustment (
    2281              :   Resolver::Adjustment &adjustment, tree expression, location_t locus)
    2282              : {
    2283          124 :   tree rvalue = expression;
    2284          124 :   location_t rvalue_locus = locus;
    2285              : 
    2286          124 :   auto actual = adjustment.get_actual ();
    2287          124 :   auto expected = adjustment.get_expected ();
    2288              : 
    2289          124 :   const auto dyn = static_cast<const TyTy::DynamicObjectType *> (expected);
    2290              : 
    2291          124 :   rust_debug ("resolve_unsized_dyn_adjustment actual={%s} dyn={%s}",
    2292              :               actual->debug_str ().c_str (), dyn->debug_str ().c_str ());
    2293              : 
    2294          124 :   return coerce_to_dyn_object (rvalue, actual, dyn, rvalue_locus);
    2295              : }
    2296              : 
    2297              : void
    2298           66 : CompileExpr::visit (HIR::RangeFromToExpr &expr)
    2299              : {
    2300           66 :   tree from = CompileExpr::Compile (expr.get_from_expr (), ctx);
    2301           66 :   tree to = CompileExpr::Compile (expr.get_to_expr (), ctx);
    2302           66 :   if (from == error_mark_node || to == error_mark_node)
    2303              :     {
    2304            0 :       translated = error_mark_node;
    2305            0 :       return;
    2306              :     }
    2307              : 
    2308           66 :   TyTy::BaseType *tyty = nullptr;
    2309           66 :   bool ok
    2310           66 :     = ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), &tyty);
    2311           66 :   rust_assert (ok);
    2312              : 
    2313           66 :   tree adt = TyTyResolveCompile::compile (ctx, tyty);
    2314              : 
    2315              :   // make the constructor
    2316           66 :   translated = Backend::constructor_expression (adt, false, {from, to}, -1,
    2317              :                                                 expr.get_locus ());
    2318              : }
    2319              : 
    2320              : void
    2321            7 : CompileExpr::visit (HIR::RangeFromExpr &expr)
    2322              : {
    2323            7 :   tree from = CompileExpr::Compile (expr.get_from_expr (), ctx);
    2324            7 :   if (from == error_mark_node)
    2325              :     {
    2326            0 :       translated = error_mark_node;
    2327            0 :       return;
    2328              :     }
    2329              : 
    2330            7 :   TyTy::BaseType *tyty = nullptr;
    2331            7 :   bool ok
    2332            7 :     = ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), &tyty);
    2333            7 :   rust_assert (ok);
    2334              : 
    2335            7 :   tree adt = TyTyResolveCompile::compile (ctx, tyty);
    2336              : 
    2337              :   // make the constructor
    2338            7 :   translated = Backend::constructor_expression (adt, false, {from}, -1,
    2339              :                                                 expr.get_locus ());
    2340              : }
    2341              : 
    2342              : void
    2343            7 : CompileExpr::visit (HIR::RangeToExpr &expr)
    2344              : {
    2345            7 :   tree to = CompileExpr::Compile (expr.get_to_expr (), ctx);
    2346            7 :   if (to == error_mark_node)
    2347              :     {
    2348            0 :       translated = error_mark_node;
    2349            0 :       return;
    2350              :     }
    2351              : 
    2352            7 :   TyTy::BaseType *tyty = nullptr;
    2353            7 :   bool ok
    2354            7 :     = ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), &tyty);
    2355            7 :   rust_assert (ok);
    2356              : 
    2357            7 :   tree adt = TyTyResolveCompile::compile (ctx, tyty);
    2358              : 
    2359              :   // make the constructor
    2360            7 :   translated
    2361            7 :     = Backend::constructor_expression (adt, false, {to}, -1, expr.get_locus ());
    2362              : }
    2363              : 
    2364              : void
    2365            0 : CompileExpr::visit (HIR::RangeFullExpr &expr)
    2366              : {
    2367            0 :   TyTy::BaseType *tyty = nullptr;
    2368            0 :   bool ok
    2369            0 :     = ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), &tyty);
    2370            0 :   rust_assert (ok);
    2371              : 
    2372            0 :   tree adt = TyTyResolveCompile::compile (ctx, tyty);
    2373            0 :   translated
    2374            0 :     = Backend::constructor_expression (adt, false, {}, -1, expr.get_locus ());
    2375            0 : }
    2376              : 
    2377              : void
    2378            7 : CompileExpr::visit (HIR::RangeFromToInclExpr &expr)
    2379              : {
    2380            7 :   tree from = CompileExpr::Compile (expr.get_from_expr (), ctx);
    2381            7 :   tree to = CompileExpr::Compile (expr.get_to_expr (), ctx);
    2382            7 :   if (from == error_mark_node || to == error_mark_node)
    2383              :     {
    2384            0 :       translated = error_mark_node;
    2385            0 :       return;
    2386              :     }
    2387              : 
    2388            7 :   TyTy::BaseType *tyty = nullptr;
    2389            7 :   bool ok
    2390            7 :     = ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), &tyty);
    2391            7 :   rust_assert (ok);
    2392              : 
    2393            7 :   tree adt = TyTyResolveCompile::compile (ctx, tyty);
    2394              : 
    2395              :   // make the constructor
    2396            7 :   translated = Backend::constructor_expression (adt, false, {from, to}, -1,
    2397              :                                                 expr.get_locus ());
    2398              : }
    2399              : 
    2400              : void
    2401          287 : CompileExpr::visit (HIR::ArrayIndexExpr &expr)
    2402              : {
    2403          287 :   tree array_reference = CompileExpr::Compile (expr.get_array_expr (), ctx);
    2404          287 :   tree index = CompileExpr::Compile (expr.get_index_expr (), ctx);
    2405              : 
    2406              :   // this might be an core::ops::index lang item situation
    2407          287 :   TyTy::FnType *fntype;
    2408          287 :   bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload (
    2409          287 :     expr.get_mappings ().get_hirid (), &fntype);
    2410          287 :   if (is_op_overload)
    2411              :     {
    2412           63 :       auto lang_item_type = LangItem::Kind::INDEX;
    2413           63 :       tree operator_overload_call
    2414           63 :         = resolve_operator_overload (lang_item_type, expr, array_reference,
    2415              :                                      index, expr.get_array_expr (),
    2416           63 :                                      expr.get_index_expr ());
    2417              : 
    2418           63 :       tree actual_type = TREE_TYPE (operator_overload_call);
    2419           63 :       bool can_indirect = TYPE_PTR_P (actual_type) || TYPE_REF_P (actual_type);
    2420           63 :       if (!can_indirect)
    2421              :         {
    2422              :           // nothing to do
    2423           35 :           translated = operator_overload_call;
    2424           63 :           return;
    2425              :         }
    2426              : 
    2427              :       // rust deref always returns a reference from this overload then we can
    2428              :       // actually do the indirection
    2429           28 :       translated
    2430           28 :         = indirect_expression (operator_overload_call, expr.get_locus ());
    2431           28 :       return;
    2432              :     }
    2433              : 
    2434              :   // lets check if the array is a reference type then we can add an
    2435              :   // indirection if required
    2436          224 :   TyTy::BaseType *array_expr_ty = nullptr;
    2437          224 :   bool ok = ctx->get_tyctx ()->lookup_type (
    2438          224 :     expr.get_array_expr ().get_mappings ().get_hirid (), &array_expr_ty);
    2439          224 :   rust_assert (ok);
    2440              : 
    2441              :   // do we need to add an indirect reference
    2442          224 :   if (array_expr_ty->get_kind () == TyTy::TypeKind::REF)
    2443              :     {
    2444           15 :       array_reference
    2445           15 :         = indirect_expression (array_reference, expr.get_locus ());
    2446              :     }
    2447              : 
    2448          224 :   translated = Backend::array_index_expression (array_reference, index,
    2449              :                                                 expr.get_locus ());
    2450              : }
    2451              : 
    2452              : void
    2453           61 : CompileExpr::visit (HIR::ClosureExpr &expr)
    2454              : {
    2455           61 :   TyTy::BaseType *closure_expr_ty = nullptr;
    2456           61 :   if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
    2457              :                                        &closure_expr_ty))
    2458              :     {
    2459            0 :       rust_fatal_error (expr.get_locus (),
    2460              :                         "did not resolve type for this ClosureExpr");
    2461              :       return;
    2462              :     }
    2463           61 :   rust_assert (closure_expr_ty->get_kind () == TyTy::TypeKind::CLOSURE);
    2464           61 :   TyTy::ClosureType *closure_tyty
    2465              :     = static_cast<TyTy::ClosureType *> (closure_expr_ty);
    2466           61 :   tree compiled_closure_tyty = TyTyResolveCompile::compile (ctx, closure_tyty);
    2467              : 
    2468              :   // generate closure function
    2469           61 :   generate_closure_function (expr, *closure_tyty, compiled_closure_tyty);
    2470              : 
    2471              :   // lets ignore state capture for now we need to instantiate the struct anyway
    2472              :   // then generate the function
    2473           61 :   std::vector<tree> vals;
    2474           82 :   for (const auto &capture : closure_tyty->get_captures ())
    2475              :     {
    2476              :       // lookup the HirId
    2477           21 :       if (auto hid = ctx->get_mappings ().lookup_node_to_hir (capture))
    2478              :         {
    2479              :           // lookup the var decl
    2480           21 :           Bvariable *var = nullptr;
    2481           21 :           bool found = ctx->lookup_var_decl (*hid, &var);
    2482           21 :           rust_assert (found);
    2483              : 
    2484              :           // FIXME
    2485              :           // this should bes based on the closure move-ability
    2486           21 :           tree var_expr = var->get_tree (expr.get_locus ());
    2487           21 :           tree val = address_expression (var_expr, expr.get_locus ());
    2488           21 :           vals.push_back (val);
    2489              :         }
    2490              :       else
    2491            0 :         rust_unreachable ();
    2492              :     }
    2493              : 
    2494           61 :   translated = Backend::constructor_expression (compiled_closure_tyty, false,
    2495              :                                                 vals, -1, expr.get_locus ());
    2496           61 : }
    2497              : 
    2498              : tree
    2499           61 : CompileExpr::generate_closure_function (HIR::ClosureExpr &expr,
    2500              :                                         TyTy::ClosureType &closure_tyty,
    2501              :                                         tree compiled_closure_tyty)
    2502              : {
    2503           61 :   TyTy::FnType *fn_tyty = nullptr;
    2504           61 :   tree compiled_fn_type
    2505           61 :     = generate_closure_fntype (expr, closure_tyty, compiled_closure_tyty,
    2506              :                                &fn_tyty);
    2507           61 :   if (compiled_fn_type == error_mark_node)
    2508              :     return error_mark_node;
    2509              : 
    2510           61 :   const Resolver::CanonicalPath &parent_canonical_path
    2511           61 :     = closure_tyty.get_ident ().path;
    2512              : 
    2513           61 :   tl::optional<NodeId> nid = ctx->get_mappings ().lookup_hir_to_node (
    2514           61 :     expr.get_mappings ().get_hirid ());
    2515           61 :   rust_assert (nid.has_value ());
    2516           61 :   auto node_id = nid.value ();
    2517              : 
    2518           61 :   Resolver::CanonicalPath path = parent_canonical_path.append (
    2519           61 :     Resolver::CanonicalPath::new_seg (node_id, "{{closure}}"));
    2520              : 
    2521           61 :   std::string ir_symbol_name = path.get ();
    2522           61 :   std::string asm_name = ctx->mangle_item (&closure_tyty, path);
    2523              : 
    2524           61 :   unsigned int flags = 0;
    2525           61 :   tree fndecl = Backend::function (compiled_fn_type, ir_symbol_name, asm_name,
    2526              :                                    flags, expr.get_locus ());
    2527              : 
    2528              :   // insert into the context
    2529           61 :   ctx->insert_function_decl (fn_tyty, fndecl);
    2530           61 :   ctx->insert_closure_decl (&closure_tyty, fndecl);
    2531              : 
    2532              :   // setup the parameters
    2533           61 :   std::vector<Bvariable *> param_vars;
    2534              : 
    2535              :   // closure self
    2536           61 :   Bvariable *self_param
    2537           61 :     = Backend::parameter_variable (fndecl, "$closure", compiled_closure_tyty,
    2538           61 :                                    expr.get_locus ());
    2539           61 :   DECL_ARTIFICIAL (self_param->get_decl ()) = 1;
    2540           61 :   param_vars.push_back (self_param);
    2541              : 
    2542              :   // push a new context
    2543           61 :   ctx->push_closure_context (expr.get_mappings ().get_hirid ());
    2544              : 
    2545              :   // setup the implicit argument captures
    2546           61 :   size_t idx = 0;
    2547           82 :   for (const auto &capture : closure_tyty.get_captures ())
    2548              :     {
    2549              :       // lookup the HirId
    2550           21 :       if (auto hid = ctx->get_mappings ().lookup_node_to_hir (capture))
    2551              :         {
    2552              :           // get the assessor
    2553           21 :           tree binding = Backend::struct_field_expression (
    2554              :             self_param->get_tree (expr.get_locus ()), idx, expr.get_locus ());
    2555           21 :           tree indirection = indirect_expression (binding, expr.get_locus ());
    2556              : 
    2557              :           // insert bindings
    2558           21 :           ctx->insert_closure_binding (*hid, indirection);
    2559              : 
    2560              :           // continue
    2561           21 :           idx++;
    2562              :         }
    2563              :       else
    2564            0 :         rust_unreachable ();
    2565              :     }
    2566              : 
    2567              :   // args tuple
    2568           61 :   tree args_type
    2569           61 :     = TyTyResolveCompile::compile (ctx, &closure_tyty.get_parameters ());
    2570           61 :   Bvariable *args_param
    2571           61 :     = Backend::parameter_variable (fndecl, "args", args_type,
    2572           61 :                                    expr.get_locus ());
    2573           61 :   param_vars.push_back (args_param);
    2574              : 
    2575              :   // setup the implicit mappings for the arguments. Since argument passing to
    2576              :   // closure functions is done via passing a tuple but the closure body expects
    2577              :   // just normal arguments this means we need to destructure them similar to
    2578              :   // what we do in MatchExpr's. This means when we have a closure-param of a we
    2579              :   // actually setup the destructure to take from the args tuple
    2580              : 
    2581           61 :   tree args_param_expr = args_param->get_tree (expr.get_locus ());
    2582           61 :   size_t i = 0;
    2583          120 :   for (auto &closure_param : expr.get_params ())
    2584              :     {
    2585           59 :       tree compiled_param_var
    2586           59 :         = Backend::struct_field_expression (args_param_expr, i,
    2587              :                                             closure_param.get_locus ());
    2588              : 
    2589           59 :       CompilePatternBindings::Compile (closure_param.get_pattern (),
    2590              :                                        compiled_param_var, ctx);
    2591           59 :       i++;
    2592              :     }
    2593              : 
    2594           61 :   if (!Backend::function_set_parameters (fndecl, param_vars))
    2595              :     {
    2596            0 :       ctx->pop_closure_context ();
    2597            0 :       return error_mark_node;
    2598              :     }
    2599              : 
    2600              :   // lookup locals
    2601           61 :   HIR::Expr &function_body = expr.get_expr ();
    2602           61 :   bool is_block_expr
    2603           61 :     = function_body.get_expression_type () == HIR::Expr::ExprType::Block;
    2604              : 
    2605           61 :   if (is_block_expr)
    2606              :     {
    2607           52 :       auto body_mappings = function_body.get_mappings ();
    2608           52 :       auto &nr_ctx
    2609           52 :         = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
    2610              : 
    2611           52 :       auto candidate = nr_ctx.values.to_rib (body_mappings.get_nodeid ());
    2612              : 
    2613           52 :       rust_assert (candidate.has_value ());
    2614              :     }
    2615              : 
    2616           61 :   tree enclosing_scope = NULL_TREE;
    2617           61 :   location_t start_location = function_body.get_locus ();
    2618           61 :   location_t end_location = function_body.get_locus ();
    2619           61 :   if (is_block_expr)
    2620              :     {
    2621           52 :       auto &body = static_cast<HIR::BlockExpr &> (function_body);
    2622           52 :       start_location = body.get_locus ();
    2623           52 :       end_location = body.get_end_locus ();
    2624              :     }
    2625              : 
    2626           61 :   tree code_block = Backend::block (fndecl, enclosing_scope, {} /*locals*/,
    2627              :                                     start_location, end_location);
    2628           61 :   ctx->push_block (code_block);
    2629              : 
    2630           61 :   TyTy::BaseType *tyret = &closure_tyty.get_result_type ();
    2631           61 :   Bvariable *return_address = nullptr;
    2632              : 
    2633           61 :   tree return_type = TyTyResolveCompile::compile (ctx, tyret);
    2634           61 :   bool address_is_taken = false;
    2635           61 :   tree ret_var_stmt = NULL_TREE;
    2636              : 
    2637           61 :   return_address
    2638           61 :     = Backend::temporary_variable (fndecl, code_block, return_type, NULL,
    2639              :                                    address_is_taken, expr.get_locus (),
    2640              :                                    &ret_var_stmt);
    2641              : 
    2642           61 :   ctx->add_statement (ret_var_stmt);
    2643              : 
    2644           61 :   ctx->push_fn (fndecl, return_address, tyret);
    2645              : 
    2646           61 :   if (is_block_expr)
    2647              :     {
    2648           52 :       auto &body = static_cast<HIR::BlockExpr &> (function_body);
    2649           52 :       compile_function_body (fndecl, body, tyret);
    2650              :     }
    2651              :   else
    2652              :     {
    2653            9 :       tree value = CompileExpr::Compile (function_body, ctx);
    2654            9 :       tree return_expr
    2655            9 :         = Backend::return_statement (fndecl, value, function_body.get_locus ());
    2656            9 :       ctx->add_statement (return_expr);
    2657              :     }
    2658              : 
    2659           61 :   tree bind_tree = ctx->pop_block ();
    2660              : 
    2661           61 :   gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR);
    2662           61 :   DECL_SAVED_TREE (fndecl) = bind_tree;
    2663              : 
    2664           61 :   ctx->pop_closure_context ();
    2665           61 :   ctx->pop_fn ();
    2666           61 :   ctx->push_function (fndecl);
    2667              : 
    2668           61 :   return fndecl;
    2669           61 : }
    2670              : 
    2671              : tree
    2672           61 : CompileExpr::generate_closure_fntype (HIR::ClosureExpr &expr,
    2673              :                                       const TyTy::ClosureType &closure_tyty,
    2674              :                                       tree compiled_closure_tyty,
    2675              :                                       TyTy::FnType **fn_tyty)
    2676              : {
    2677              :   // grab the specified_bound
    2678           61 :   rust_assert (closure_tyty.num_specified_bounds () == 1);
    2679           61 :   const TyTy::TypeBoundPredicate &predicate
    2680           61 :     = *closure_tyty.get_specified_bounds ().begin ();
    2681              : 
    2682              :   // ensure the fn_once_output associated type is set
    2683           61 :   closure_tyty.setup_fn_once_output ();
    2684              : 
    2685              :   // the function signature is based on the trait bound that the closure
    2686              :   // implements which is determined at the type resolution time
    2687              :   //
    2688              :   // https://github.com/rust-lang/rust/blob/7807a694c2f079fd3f395821bcc357eee8650071/library/core/src/ops/function.rs#L54-L71
    2689              : 
    2690           61 :   TyTy::TypeBoundPredicateItem item = TyTy::TypeBoundPredicateItem::error ();
    2691           61 :   if (predicate.get_name ().compare ("FnOnce") == 0)
    2692              :     {
    2693          122 :       item = predicate.lookup_associated_item ("call_once").value ();
    2694              :     }
    2695            0 :   else if (predicate.get_name ().compare ("FnMut") == 0)
    2696              :     {
    2697            0 :       item = predicate.lookup_associated_item ("call_mut").value ();
    2698              :     }
    2699            0 :   else if (predicate.get_name ().compare ("Fn") == 0)
    2700              :     {
    2701            0 :       item = predicate.lookup_associated_item ("call").value ();
    2702              :     }
    2703              :   else
    2704              :     {
    2705              :       // FIXME error message?
    2706            0 :       rust_unreachable ();
    2707              :       return error_mark_node;
    2708              :     }
    2709              : 
    2710           61 :   rust_assert (!item.is_error ());
    2711              : 
    2712           61 :   TyTy::BaseType *item_tyty = item.get_tyty_for_receiver (&closure_tyty);
    2713           61 :   rust_assert (item_tyty->get_kind () == TyTy::TypeKind::FNDEF);
    2714           61 :   *fn_tyty = static_cast<TyTy::FnType *> (item_tyty);
    2715           61 :   return TyTyResolveCompile::compile (ctx, item_tyty);
    2716           61 : }
    2717              : 
    2718              : bool
    2719        10520 : CompileExpr::generate_possible_fn_trait_call (HIR::CallExpr &expr,
    2720              :                                               tree receiver, tree *result)
    2721              : {
    2722        10520 :   TyTy::FnType *fn_sig = nullptr;
    2723        10520 :   bool found_overload = ctx->get_tyctx ()->lookup_operator_overload (
    2724        10520 :     expr.get_mappings ().get_hirid (), &fn_sig);
    2725        10520 :   if (!found_overload)
    2726              :     return false;
    2727              : 
    2728           60 :   auto id = fn_sig->get_ty_ref ();
    2729           60 :   auto dId = fn_sig->get_id ();
    2730              : 
    2731           60 :   tree function = error_mark_node;
    2732           60 :   bool found_closure = ctx->lookup_function_decl (id, &function, dId, fn_sig);
    2733           60 :   if (!found_closure)
    2734              :     {
    2735              :       // something went wrong we still return true as this was meant to be an fn
    2736              :       // trait call
    2737            0 :       *result = error_mark_node;
    2738            0 :       return true;
    2739              :     }
    2740              : 
    2741              :   // need to apply any autoderef's to the self argument
    2742           60 :   HIR::Expr &fnexpr = expr.get_fnexpr ();
    2743           60 :   HirId autoderef_mappings_id = fnexpr.get_mappings ().get_hirid ();
    2744           60 :   std::vector<Resolver::Adjustment> *adjustments = nullptr;
    2745           60 :   bool ok = ctx->get_tyctx ()->lookup_autoderef_mappings (autoderef_mappings_id,
    2746              :                                                           &adjustments);
    2747           60 :   rust_assert (ok);
    2748              : 
    2749              :   // apply adjustments for the fn call
    2750           60 :   tree self = resolve_adjustements (*adjustments, receiver, expr.get_locus ());
    2751              : 
    2752              :   // resolve the arguments
    2753           60 :   std::vector<tree> tuple_arg_vals;
    2754          120 :   for (auto &argument : expr.get_arguments ())
    2755              :     {
    2756           60 :       auto rvalue = CompileExpr::Compile (*argument, ctx);
    2757           60 :       tuple_arg_vals.push_back (rvalue);
    2758              :     }
    2759              : 
    2760              :   // this is always the 2nd argument in the function signature
    2761           60 :   tree fnty = TREE_TYPE (function);
    2762           60 :   tree fn_arg_tys = TYPE_ARG_TYPES (fnty);
    2763           60 :   tree tuple_args_tyty_chain = TREE_CHAIN (fn_arg_tys);
    2764           60 :   tree tuple_args_tyty = TREE_VALUE (tuple_args_tyty_chain);
    2765              : 
    2766           60 :   tree tuple_args
    2767           60 :     = Backend::constructor_expression (tuple_args_tyty, false, tuple_arg_vals,
    2768           60 :                                        -1, expr.get_locus ());
    2769              : 
    2770              :   // args are always self, and the tuple of the args we are passing where
    2771              :   // self is the path of the call-expr in this case the fn_address
    2772           60 :   std::vector<tree> args;
    2773           60 :   args.push_back (self);
    2774           60 :   args.push_back (tuple_args);
    2775              : 
    2776           60 :   tree call_address = address_expression (function, expr.get_locus ());
    2777           60 :   *result
    2778           60 :     = Backend::call_expression (call_address, args, nullptr /* static chain ?*/,
    2779              :                                 expr.get_locus ());
    2780           60 :   return true;
    2781           60 : }
    2782              : 
    2783              : tree
    2784            2 : CompileExpr::construct_block_label (HIR::BlockExpr &expr)
    2785              : {
    2786            2 :   if (expr.has_label ())
    2787              :     {
    2788            2 :       fncontext fnctx = ctx->peek_fn ();
    2789            2 :       HIR::LoopLabel &label = expr.get_label ();
    2790            2 :       std::string label_name = label.get_lifetime ().get_name ();
    2791            2 :       HirId label_id = label.get_lifetime ().get_mappings ().get_hirid ();
    2792            2 :       tree label_decl
    2793            2 :         = Backend::label (fnctx.fndecl, label_name, label.get_locus ());
    2794            2 :       tree label_expr = Backend::label_definition_statement (label_decl);
    2795            2 :       ctx->insert_label_decl (label_id, label_decl);
    2796            2 :       return label_expr;
    2797            2 :     }
    2798              :   return NULL_TREE;
    2799              : }
    2800              : 
    2801              : tree
    2802            2 : CompileExpr::lookup_label (NodeId to_be_resolved)
    2803              : {
    2804            2 :   HirId ref = resolve_NodeId (to_be_resolved);
    2805            2 :   tree label = NULL_TREE;
    2806            2 :   rust_assert (ctx->lookup_label_decl (ref, &label)
    2807              :                && "failed to lookup a label");
    2808            2 :   return label;
    2809              : }
    2810              : 
    2811              : Bvariable *
    2812            2 : CompileExpr::lookup_temp_var (NodeId to_be_resolved)
    2813              : {
    2814            2 :   HirId ref = resolve_NodeId (to_be_resolved);
    2815            2 :   Bvariable *ltemp = nullptr;
    2816            2 :   rust_assert (ctx->lookup_var_decl (ref, &ltemp)
    2817              :                && "failed to lookup a temp var");
    2818            2 :   return ltemp;
    2819              : }
    2820              : 
    2821              : HirId
    2822            4 : CompileExpr::resolve_NodeId (NodeId to_be_resolved)
    2823              : {
    2824            4 :   auto &nr_ctx
    2825            4 :     = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
    2826              : 
    2827            4 :   NodeId resolved_node_id;
    2828            4 :   resolved_node_id = nr_ctx.lookup (to_be_resolved).value ();
    2829              : 
    2830            4 :   HirId ref
    2831            4 :     = ctx->get_mappings ().lookup_node_to_hir (resolved_node_id).value ();
    2832            4 :   return ref;
    2833              : }
    2834              : 
    2835              : } // namespace Compile
    2836              : } // 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.