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