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