@@ -1589,9 +1589,7 @@ CompileExpr::visit (HIR::CallExpr &expr)
1589
1589
}
1590
1590
1591
1591
// must be a tuple constructor
1592
- bool is_fn = tyty->get_kind () == TyTy::TypeKind::FNDEF
1593
- || tyty->get_kind () == TyTy::TypeKind::FNPTR;
1594
- bool is_adt_ctor = !is_fn;
1592
+ bool is_adt_ctor = tyty->get_kind () == TyTy::TypeKind::ADT;
1595
1593
if (is_adt_ctor)
1596
1594
{
1597
1595
rust_assert (tyty->get_kind () == TyTy::TypeKind::ADT);
@@ -1692,20 +1690,71 @@ CompileExpr::visit (HIR::CallExpr &expr)
1692
1690
return true ;
1693
1691
};
1694
1692
1693
+ auto fn_address = CompileExpr::Compile (expr.get_fnexpr (), ctx);
1694
+
1695
+ // is this a closure call?
1696
+ if (RS_CLOSURE_TYPE_P (TREE_TYPE (fn_address)))
1697
+ {
1698
+ rust_assert (tyty->get_kind () == TyTy::TypeKind::CLOSURE);
1699
+ TyTy::ClosureType *closure = static_cast <TyTy::ClosureType *> (tyty);
1700
+
1701
+ std::vector<tree> tuple_arg_vals;
1702
+ for (auto &argument : expr.get_arguments ())
1703
+ {
1704
+ auto rvalue = CompileExpr::Compile (argument.get (), ctx);
1705
+ tuple_arg_vals.push_back (rvalue);
1706
+ }
1707
+
1708
+ tree tuple_args_tyty
1709
+ = TyTyResolveCompile::compile (ctx, &closure->get_parameters ());
1710
+ tree tuple_args
1711
+ = ctx->get_backend ()->constructor_expression (tuple_args_tyty, false ,
1712
+ tuple_arg_vals, -1 ,
1713
+ expr.get_locus ());
1714
+
1715
+ // need to apply any autoderef's to the self argument
1716
+ HirId autoderef_mappings_id = expr.get_mappings ().get_hirid ();
1717
+ std::vector<Resolver::Adjustment> *adjustments = nullptr ;
1718
+ bool ok
1719
+ = ctx->get_tyctx ()->lookup_autoderef_mappings (autoderef_mappings_id,
1720
+ &adjustments);
1721
+ rust_assert (ok);
1722
+
1723
+ // apply adjustments for the fn call
1724
+ tree self
1725
+ = resolve_adjustements (*adjustments, fn_address, expr.get_locus ());
1726
+
1727
+ // args are always self, and the tuple of the args we are passing where
1728
+ // self is the path of the call-expr in this case the fn_address
1729
+ std::vector<tree> args;
1730
+ args.push_back (self);
1731
+ args.push_back (tuple_args);
1732
+
1733
+ // get the fn call address
1734
+ tree closure_call_site = ctx->lookup_closure_decl (closure);
1735
+ tree closure_call_address
1736
+ = address_expression (closure_call_site, expr.get_locus ());
1737
+ translated
1738
+ = ctx->get_backend ()->call_expression (closure_call_address, args,
1739
+ nullptr /* static chain ?*/ ,
1740
+ expr.get_locus ());
1741
+ return ;
1742
+ }
1743
+
1695
1744
bool is_varadic = false ;
1696
1745
if (tyty->get_kind () == TyTy::TypeKind::FNDEF)
1697
1746
{
1698
1747
const TyTy::FnType *fn = static_cast <const TyTy::FnType *> (tyty);
1699
1748
is_varadic = fn->is_varadic ();
1700
1749
}
1701
1750
1702
- size_t required_num_args;
1751
+ size_t required_num_args = expr. get_arguments (). size () ;
1703
1752
if (tyty->get_kind () == TyTy::TypeKind::FNDEF)
1704
1753
{
1705
1754
const TyTy::FnType *fn = static_cast <const TyTy::FnType *> (tyty);
1706
1755
required_num_args = fn->num_params ();
1707
1756
}
1708
- else
1757
+ else if (tyty-> get_kind () == TyTy::TypeKind::FNPTR)
1709
1758
{
1710
1759
const TyTy::FnPtr *fn = static_cast <const TyTy::FnPtr *> (tyty);
1711
1760
required_num_args = fn->num_params ();
@@ -1746,8 +1795,7 @@ CompileExpr::visit (HIR::CallExpr &expr)
1746
1795
args.push_back (rvalue);
1747
1796
}
1748
1797
1749
- // must be a call to a function
1750
- auto fn_address = CompileExpr::Compile (expr.get_fnexpr (), ctx);
1798
+ // must be a regular call to a function
1751
1799
translated = ctx->get_backend ()->call_expression (fn_address, args, nullptr ,
1752
1800
expr.get_locus ());
1753
1801
}
@@ -2806,7 +2854,223 @@ CompileExpr::visit (HIR::ArrayIndexExpr &expr)
2806
2854
void
2807
2855
CompileExpr::visit (HIR::ClosureExpr &expr)
2808
2856
{
2809
- gcc_unreachable ();
2857
+ TyTy::BaseType *closure_expr_ty = nullptr ;
2858
+ if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
2859
+ &closure_expr_ty))
2860
+ {
2861
+ rust_fatal_error (expr.get_locus (),
2862
+ " did not resolve type for this ClosureExpr" );
2863
+ return ;
2864
+ }
2865
+ rust_assert (closure_expr_ty->get_kind () == TyTy::TypeKind::CLOSURE);
2866
+ TyTy::ClosureType *closure_tyty
2867
+ = static_cast <TyTy::ClosureType *> (closure_expr_ty);
2868
+ tree compiled_closure_tyty = TyTyResolveCompile::compile (ctx, closure_tyty);
2869
+
2870
+ // generate closure function
2871
+ generate_closure_function (expr, *closure_tyty, compiled_closure_tyty);
2872
+
2873
+ // lets ignore state capture for now we need to instantiate the struct anyway
2874
+ // then generate the function
2875
+
2876
+ std::vector<tree> vals;
2877
+ // TODO
2878
+ // setup argument captures based on the mode?
2879
+
2880
+ translated
2881
+ = ctx->get_backend ()->constructor_expression (compiled_closure_tyty, false ,
2882
+ vals, -1 , expr.get_locus ());
2883
+ }
2884
+
2885
+ tree
2886
+ CompileExpr::generate_closure_function (HIR::ClosureExpr &expr,
2887
+ TyTy::ClosureType &closure_tyty,
2888
+ tree compiled_closure_tyty)
2889
+ {
2890
+ TyTy::FnType *fn_tyty = nullptr ;
2891
+ tree compiled_fn_type
2892
+ = generate_closure_fntype (expr, closure_tyty, compiled_closure_tyty,
2893
+ &fn_tyty);
2894
+ if (compiled_fn_type == error_mark_node)
2895
+ return error_mark_node;
2896
+
2897
+ const Resolver::CanonicalPath &parent_canonical_path
2898
+ = closure_tyty.get_ident ().path ;
2899
+ Resolver::CanonicalPath path = parent_canonical_path.append (
2900
+ Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, " {{closure}}" ));
2901
+
2902
+ std::string ir_symbol_name = path.get ();
2903
+ std::string asm_name = ctx->mangle_item (&closure_tyty, path);
2904
+
2905
+ unsigned int flags = 0 ;
2906
+ tree fndecl
2907
+ = ctx->get_backend ()->function (compiled_fn_type, ir_symbol_name, asm_name,
2908
+ flags, expr.get_locus ());
2909
+
2910
+ // insert into the context
2911
+ ctx->insert_function_decl (fn_tyty, fndecl);
2912
+ ctx->insert_closure_decl (&closure_tyty, fndecl);
2913
+
2914
+ // setup the parameters
2915
+ std::vector<Bvariable *> param_vars;
2916
+
2917
+ // closure self
2918
+ Bvariable *self_param
2919
+ = ctx->get_backend ()->parameter_variable (fndecl, " $closure" ,
2920
+ compiled_closure_tyty,
2921
+ expr.get_locus ());
2922
+ DECL_ARTIFICIAL (self_param->get_decl ()) = 1 ;
2923
+ param_vars.push_back (self_param);
2924
+
2925
+ // setup the implicit argument captures
2926
+ // TODO
2927
+
2928
+ // args tuple
2929
+ tree args_type
2930
+ = TyTyResolveCompile::compile (ctx, &closure_tyty.get_parameters ());
2931
+ Bvariable *args_param
2932
+ = ctx->get_backend ()->parameter_variable (fndecl, " args" , args_type,
2933
+ expr.get_locus ());
2934
+ param_vars.push_back (args_param);
2935
+
2936
+ // setup the implicit mappings for the arguments. Since argument passing to
2937
+ // closure functions is done via passing a tuple but the closure body expects
2938
+ // just normal arguments this means we need to destructure them similar to
2939
+ // what we do in MatchExpr's. This means when we have a closure-param of a we
2940
+ // actually setup the destructure to take from the args tuple
2941
+
2942
+ tree args_param_expr = args_param->get_tree (expr.get_locus ());
2943
+ size_t i = 0 ;
2944
+ for (auto &closure_param : expr.get_params ())
2945
+ {
2946
+ tree compiled_param_var = ctx->get_backend ()->struct_field_expression (
2947
+ args_param_expr, i, closure_param.get_locus ());
2948
+
2949
+ const HIR::Pattern ¶m_pattern = *closure_param.get_pattern ();
2950
+ ctx->insert_pattern_binding (
2951
+ param_pattern.get_pattern_mappings ().get_hirid (), compiled_param_var);
2952
+ i++;
2953
+ }
2954
+
2955
+ if (!ctx->get_backend ()->function_set_parameters (fndecl, param_vars))
2956
+ return error_mark_node;
2957
+
2958
+ // lookup locals
2959
+ HIR::Expr *function_body = expr.get_expr ().get ();
2960
+ auto body_mappings = function_body->get_mappings ();
2961
+ Resolver::Rib *rib = nullptr ;
2962
+ bool ok
2963
+ = ctx->get_resolver ()->find_name_rib (body_mappings.get_nodeid (), &rib);
2964
+ rust_assert (ok);
2965
+
2966
+ std::vector<Bvariable *> locals
2967
+ = compile_locals_for_block (ctx, *rib, fndecl);
2968
+
2969
+ tree enclosing_scope = NULL_TREE;
2970
+ Location start_location = function_body->get_locus ();
2971
+ Location end_location = function_body->get_locus ();
2972
+ bool is_block_expr
2973
+ = function_body->get_expression_type () == HIR::Expr::ExprType::Block;
2974
+ if (is_block_expr)
2975
+ {
2976
+ HIR::BlockExpr *body = static_cast <HIR::BlockExpr *> (function_body);
2977
+ start_location = body->get_locus ();
2978
+ end_location = body->get_end_locus ();
2979
+ }
2980
+
2981
+ tree code_block = ctx->get_backend ()->block (fndecl, enclosing_scope, locals,
2982
+ start_location, end_location);
2983
+ ctx->push_block (code_block);
2984
+
2985
+ TyTy::BaseType *tyret = &closure_tyty.get_result_type ();
2986
+ bool function_has_return = !closure_tyty.get_result_type ().is_unit ();
2987
+ Bvariable *return_address = nullptr ;
2988
+ if (function_has_return)
2989
+ {
2990
+ tree return_type = TyTyResolveCompile::compile (ctx, tyret);
2991
+
2992
+ bool address_is_taken = false ;
2993
+ tree ret_var_stmt = NULL_TREE;
2994
+
2995
+ return_address = ctx->get_backend ()->temporary_variable (
2996
+ fndecl, code_block, return_type, NULL , address_is_taken,
2997
+ expr.get_locus (), &ret_var_stmt);
2998
+
2999
+ ctx->add_statement (ret_var_stmt);
3000
+ }
3001
+
3002
+ ctx->push_fn (fndecl, return_address);
3003
+
3004
+ if (is_block_expr)
3005
+ {
3006
+ HIR::BlockExpr *body = static_cast <HIR::BlockExpr *> (function_body);
3007
+ compile_function_body (ctx, fndecl, *body, true );
3008
+ }
3009
+ else
3010
+ {
3011
+ tree value = CompileExpr::Compile (function_body, ctx);
3012
+ tree return_expr
3013
+ = ctx->get_backend ()->return_statement (fndecl, {value},
3014
+ function_body->get_locus ());
3015
+ ctx->add_statement (return_expr);
3016
+ }
3017
+
3018
+ tree bind_tree = ctx->pop_block ();
3019
+
3020
+ gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR);
3021
+ DECL_SAVED_TREE (fndecl) = bind_tree;
3022
+
3023
+ ctx->pop_fn ();
3024
+ ctx->push_function (fndecl);
3025
+
3026
+ return fndecl;
3027
+ }
3028
+
3029
+ tree
3030
+ CompileExpr::generate_closure_fntype (HIR::ClosureExpr &expr,
3031
+ const TyTy::ClosureType &closure_tyty,
3032
+ tree compiled_closure_tyty,
3033
+ TyTy::FnType **fn_tyty)
3034
+ {
3035
+ // grab the specified_bound
3036
+ rust_assert (closure_tyty.num_specified_bounds () == 1 );
3037
+ const TyTy::TypeBoundPredicate &predicate
3038
+ = *closure_tyty.get_specified_bounds ().begin ();
3039
+
3040
+ // ensure the fn_once_output associated type is set
3041
+ closure_tyty.setup_fn_once_output ();
3042
+
3043
+ // the function signature is based on the trait bound that the closure
3044
+ // implements which is determined at the type resolution time
3045
+ //
3046
+ // https://github.com/rust-lang/rust/blob/7807a694c2f079fd3f395821bcc357eee8650071/library/core/src/ops/function.rs#L54-L71
3047
+
3048
+ TyTy::TypeBoundPredicateItem item = TyTy::TypeBoundPredicateItem::error ();
3049
+ if (predicate.get_name ().compare (" FnOnce" ) == 0 )
3050
+ {
3051
+ item = predicate.lookup_associated_item (" call_once" );
3052
+ }
3053
+ else if (predicate.get_name ().compare (" FnMut" ) == 0 )
3054
+ {
3055
+ item = predicate.lookup_associated_item (" call_mut" );
3056
+ }
3057
+ else if (predicate.get_name ().compare (" Fn" ) == 0 )
3058
+ {
3059
+ item = predicate.lookup_associated_item (" call" );
3060
+ }
3061
+ else
3062
+ {
3063
+ // FIXME error message?
3064
+ gcc_unreachable ();
3065
+ return error_mark_node;
3066
+ }
3067
+
3068
+ rust_assert (!item.is_error ());
3069
+
3070
+ TyTy::BaseType *item_tyty = item.get_tyty_for_receiver (&closure_tyty);
3071
+ rust_assert (item_tyty->get_kind () == TyTy::TypeKind::FNDEF);
3072
+ *fn_tyty = static_cast <TyTy::FnType *> (item_tyty);
3073
+ return TyTyResolveCompile::compile (ctx, item_tyty);
2810
3074
}
2811
3075
2812
3076
} // namespace Compile
0 commit comments