Skip to content

Commit 8d718fe

Browse files
philbertydkm
authored andcommitted
Support Closure calls as generic trait bounds
Addresses #195
1 parent a0befff commit 8d718fe

File tree

3 files changed

+104
-47
lines changed

3 files changed

+104
-47
lines changed

gcc/rust/backend/rust-compile-expr.cc

+69-47
Original file line numberDiff line numberDiff line change
@@ -1693,53 +1693,10 @@ CompileExpr::visit (HIR::CallExpr &expr)
16931693
auto fn_address = CompileExpr::Compile (expr.get_fnexpr (), ctx);
16941694

16951695
// 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-
}
1696+
bool possible_trait_call
1697+
= generate_possible_fn_trait_call (expr, fn_address, &translated);
1698+
if (possible_trait_call)
1699+
return;
17431700

17441701
bool is_varadic = false;
17451702
if (tyty->get_kind () == TyTy::TypeKind::FNDEF)
@@ -3073,5 +3030,70 @@ CompileExpr::generate_closure_fntype (HIR::ClosureExpr &expr,
30733030
return TyTyResolveCompile::compile (ctx, item_tyty);
30743031
}
30753032

3033+
bool
3034+
CompileExpr::generate_possible_fn_trait_call (HIR::CallExpr &expr,
3035+
tree receiver, tree *result)
3036+
{
3037+
TyTy::FnType *fn_sig = nullptr;
3038+
bool found_overload = ctx->get_tyctx ()->lookup_operator_overload (
3039+
expr.get_mappings ().get_hirid (), &fn_sig);
3040+
if (!found_overload)
3041+
return false;
3042+
3043+
auto id = fn_sig->get_ty_ref ();
3044+
auto dId = fn_sig->get_id ();
3045+
3046+
tree function = error_mark_node;
3047+
bool found_closure = ctx->lookup_function_decl (id, &function, dId, fn_sig);
3048+
if (!found_closure)
3049+
{
3050+
// something went wrong we still return true as this was meant to be an fn
3051+
// trait call
3052+
*result = error_mark_node;
3053+
return true;
3054+
}
3055+
3056+
// need to apply any autoderef's to the self argument
3057+
HirId autoderef_mappings_id = expr.get_mappings ().get_hirid ();
3058+
std::vector<Resolver::Adjustment> *adjustments = nullptr;
3059+
bool ok = ctx->get_tyctx ()->lookup_autoderef_mappings (autoderef_mappings_id,
3060+
&adjustments);
3061+
rust_assert (ok);
3062+
3063+
// apply adjustments for the fn call
3064+
tree self = resolve_adjustements (*adjustments, receiver, expr.get_locus ());
3065+
3066+
// resolve the arguments
3067+
std::vector<tree> tuple_arg_vals;
3068+
for (auto &argument : expr.get_arguments ())
3069+
{
3070+
auto rvalue = CompileExpr::Compile (argument.get (), ctx);
3071+
tuple_arg_vals.push_back (rvalue);
3072+
}
3073+
3074+
// this is always the 2nd argument in the function signature
3075+
tree fnty = TREE_TYPE (function);
3076+
tree fn_arg_tys = TYPE_ARG_TYPES (fnty);
3077+
tree tuple_args_tyty_chain = TREE_CHAIN (fn_arg_tys);
3078+
tree tuple_args_tyty = TREE_VALUE (tuple_args_tyty_chain);
3079+
3080+
tree tuple_args
3081+
= ctx->get_backend ()->constructor_expression (tuple_args_tyty, false,
3082+
tuple_arg_vals, -1,
3083+
expr.get_locus ());
3084+
3085+
// args are always self, and the tuple of the args we are passing where
3086+
// self is the path of the call-expr in this case the fn_address
3087+
std::vector<tree> args;
3088+
args.push_back (self);
3089+
args.push_back (tuple_args);
3090+
3091+
tree call_address = address_expression (function, expr.get_locus ());
3092+
*result = ctx->get_backend ()->call_expression (call_address, args,
3093+
nullptr /* static chain ?*/,
3094+
expr.get_locus ());
3095+
return true;
3096+
}
3097+
30763098
} // namespace Compile
30773099
} // namespace Rust

gcc/rust/backend/rust-compile-expr.h

+3
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ class CompileExpr : private HIRCompileBase, protected HIR::HIRExpressionVisitor
152152
tree compiled_closure_tyty,
153153
TyTy::FnType **fn_tyty);
154154

155+
bool generate_possible_fn_trait_call (HIR::CallExpr &expr, tree receiver,
156+
tree *result);
157+
155158
private:
156159
CompileExpr (Context *ctx);
157160

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// { dg-output "3\n" }
2+
extern "C" {
3+
fn printf(s: *const i8, ...);
4+
}
5+
6+
#[lang = "fn_once"]
7+
pub trait FnOnce<Args> {
8+
#[lang = "fn_once_output"]
9+
type Output;
10+
11+
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
12+
}
13+
14+
fn f<F: FnOnce(i32) -> i32>(g: F) {
15+
let call = g(1);
16+
unsafe {
17+
let a = "%i\n\0";
18+
let b = a as *const str;
19+
let c = b as *const i8;
20+
21+
printf(c, call);
22+
}
23+
}
24+
25+
pub fn main() -> i32 {
26+
let a = |i: i32| {
27+
let b = i + 2;
28+
b
29+
};
30+
f(a);
31+
0
32+
}

0 commit comments

Comments
 (0)