aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/backend/rust-compile.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/rust/backend/rust-compile.cc')
-rw-r--r--gcc/rust/backend/rust-compile.cc255
1 files changed, 240 insertions, 15 deletions
diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc
index f0e26dc..58c679f 100644
--- a/gcc/rust/backend/rust-compile.cc
+++ b/gcc/rust/backend/rust-compile.cc
@@ -108,6 +108,9 @@ CompileExpr::visit (HIR::CallExpr &expr)
void
CompileExpr::visit (HIR::MethodCallExpr &expr)
{
+ // method receiver
+ Bexpression *self = CompileExpr::Compile (expr.get_receiver ().get (), ctx);
+
// lookup the resolved name
NodeId resolved_node_id = UNKNOWN_NODEID;
if (!ctx->get_resolver ()->lookup_resolved_name (
@@ -134,6 +137,110 @@ CompileExpr::visit (HIR::MethodCallExpr &expr)
rust_assert (lookup_fntype->get_kind () == TyTy::TypeKind::FNDEF);
TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup_fntype);
+ TyTy::BaseType *receiver = nullptr;
+ ok = ctx->get_tyctx ()->lookup_receiver (expr.get_mappings ().get_hirid (),
+ &receiver);
+ rust_assert (ok);
+
+ bool is_dyn_dispatch
+ = receiver->get_root ()->get_kind () == TyTy::TypeKind::DYNAMIC;
+ bool is_generic_receiver = receiver->get_kind () == TyTy::TypeKind::PARAM;
+ if (is_generic_receiver)
+ {
+ TyTy::ParamType *p = static_cast<TyTy::ParamType *> (receiver);
+ receiver = p->resolve ();
+ }
+
+ if (is_dyn_dispatch)
+ {
+ TyTy::DynamicObjectType *dyn
+ = static_cast<TyTy::DynamicObjectType *> (receiver->get_root ());
+
+ size_t offs = 0;
+ const Resolver::TraitItemReference *ref = nullptr;
+ for (auto &item : dyn->get_object_items ())
+ {
+ auto t = item->get_tyty ();
+ rust_assert (t->get_kind () == TyTy::TypeKind::FNDEF);
+ auto ft = static_cast<TyTy::FnType *> (t);
+
+ if (ft->get_id () == fntype->get_id ())
+ {
+ ref = item;
+ break;
+ }
+ offs++;
+ }
+
+ if (ref == nullptr)
+ {
+ translated = ctx->get_backend ()->error_expression ();
+ return;
+ }
+
+ // get any indirection sorted out
+ auto receiver_ref = self;
+ if (receiver->get_kind () == TyTy::TypeKind::REF)
+ {
+ TyTy::ReferenceType *r
+ = static_cast<TyTy::ReferenceType *> (receiver);
+ auto indirect_ty = r->get_base ();
+ Btype *indrect_compiled_tyty
+ = TyTyResolveCompile::compile (ctx, indirect_ty);
+
+ Bexpression *indirect
+ = ctx->get_backend ()->indirect_expression (indrect_compiled_tyty,
+ receiver_ref, true,
+ expr.get_locus ());
+ receiver_ref = indirect;
+ }
+
+ // access the offs + 1 for the fnptr and offs=0 for the reciever obj
+ Bexpression *self_argument
+ = ctx->get_backend ()->struct_field_expression (receiver_ref, 0,
+ expr.get_locus ());
+
+ // access the vtable for the fn
+ Bexpression *fn_vtable_access
+ = ctx->get_backend ()->struct_field_expression (receiver_ref, offs + 1,
+ expr.get_locus ());
+
+ // cast it to the correct fntype
+ Btype *expected_fntype = TyTyResolveCompile::compile (ctx, fntype, true);
+ Bexpression *fn_convert_expr
+ = ctx->get_backend ()->convert_expression (expected_fntype,
+ fn_vtable_access,
+ expr.get_locus ());
+
+ fncontext fnctx = ctx->peek_fn ();
+ Bblock *enclosing_scope = ctx->peek_enclosing_scope ();
+ bool is_address_taken = false;
+ Bstatement *ret_var_stmt = nullptr;
+
+ Bvariable *fn_convert_expr_tmp = ctx->get_backend ()->temporary_variable (
+ fnctx.fndecl, enclosing_scope, expected_fntype, fn_convert_expr,
+ is_address_taken, expr.get_locus (), &ret_var_stmt);
+ ctx->add_statement (ret_var_stmt);
+
+ std::vector<Bexpression *> args;
+ args.push_back (self_argument);
+ expr.iterate_params ([&] (HIR::Expr *p) mutable -> bool {
+ Bexpression *compiled_expr = CompileExpr::Compile (p, ctx);
+ rust_assert (compiled_expr != nullptr);
+ args.push_back (compiled_expr);
+ return true;
+ });
+
+ Bexpression *fn_expr
+ = ctx->get_backend ()->var_expression (fn_convert_expr_tmp,
+ expr.get_locus ());
+
+ translated
+ = ctx->get_backend ()->call_expression (fnctx.fndecl, fn_expr, args,
+ nullptr, expr.get_locus ());
+ return;
+ }
+
// lookup compiled functions
Bfunction *fn = nullptr;
if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &fn))
@@ -157,17 +264,6 @@ CompileExpr::visit (HIR::MethodCallExpr &expr)
trait->get_mappings ().get_defid (), &trait_ref);
rust_assert (ok);
- TyTy::BaseType *receiver = nullptr;
- ok = ctx->get_tyctx ()->lookup_receiver (
- expr.get_mappings ().get_hirid (), &receiver);
- rust_assert (ok);
-
- if (receiver->get_kind () == TyTy::TypeKind::PARAM)
- {
- TyTy::ParamType *p = static_cast<TyTy::ParamType *> (receiver);
- receiver = p->resolve ();
- }
-
// the type resolver can only resolve type bounds to their trait
// item so its up to us to figure out if this path should resolve
// to an trait-impl-block-item or if it can be defaulted to the
@@ -290,10 +386,6 @@ CompileExpr::visit (HIR::MethodCallExpr &expr)
std::vector<Bexpression *> args;
- // method receiver
- Bexpression *self = CompileExpr::Compile (expr.get_receiver ().get (), ctx);
- rust_assert (self != nullptr);
-
// lookup the autoderef mappings
std::vector<Resolver::Adjustment> *adjustments = nullptr;
ok = ctx->get_tyctx ()->lookup_autoderef_mappings (
@@ -579,5 +671,138 @@ HIRCompileBase::compile_locals_for_block (Resolver::Rib &rib, Bfunction *fndecl,
return true;
}
+
+Bexpression *
+HIRCompileBase::coercion_site (Bexpression *compiled_ref,
+ TyTy::BaseType *actual, TyTy::BaseType *expected,
+ Location locus)
+{
+ auto root_actual_kind = actual->get_root ()->get_kind ();
+ auto root_expected_kind = expected->get_root ()->get_kind ();
+
+ if (root_expected_kind == TyTy::TypeKind::DYNAMIC
+ && root_actual_kind != TyTy::TypeKind::DYNAMIC)
+ {
+ TyTy::DynamicObjectType *dyn
+ = static_cast<TyTy::DynamicObjectType *> (expected->get_root ());
+ return coerce_to_dyn_object (compiled_ref, actual, expected, dyn, locus);
+ }
+
+ return compiled_ref;
+}
+
+Bexpression *
+HIRCompileBase::coerce_to_dyn_object (Bexpression *compiled_ref,
+ TyTy::BaseType *actual,
+ TyTy::BaseType *expected,
+ TyTy::DynamicObjectType *ty,
+ Location locus)
+{
+ Btype *dynamic_object = TyTyResolveCompile::compile (ctx, ty);
+
+ //' this assumes ordering and current the structure is
+ // __trait_object_ptr
+ // [list of function ptrs]
+
+ std::vector<Bexpression *> vals;
+ vals.push_back (compiled_ref);
+ for (auto &item : ty->get_object_items ())
+ {
+ // compute the address of each method item
+ auto address = compute_address_for_trait_item (item, actual->get_root ());
+ vals.push_back (address);
+ }
+
+ Bexpression *constructed_trait_object
+ = ctx->get_backend ()->constructor_expression (dynamic_object, vals, -1,
+
+ locus);
+
+ fncontext fnctx = ctx->peek_fn ();
+ Bblock *enclosing_scope = ctx->peek_enclosing_scope ();
+ bool is_address_taken = false;
+ Bstatement *ret_var_stmt = nullptr;
+
+ Bvariable *dyn_tmp = ctx->get_backend ()->temporary_variable (
+ fnctx.fndecl, enclosing_scope, dynamic_object, constructed_trait_object,
+ is_address_taken, locus, &ret_var_stmt);
+ ctx->add_statement (ret_var_stmt);
+
+ // FIXME this needs to be more generic to apply any covariance
+
+ auto e = expected;
+ std::vector<Resolver::Adjustment> adjustments;
+ while (e->get_kind () == TyTy::TypeKind::REF)
+ {
+ auto r = static_cast<TyTy::ReferenceType *> (e);
+ e = r->get_base ();
+
+ if (r->is_mutable ())
+ adjustments.push_back (
+ Resolver::Adjustment (Resolver::Adjustment::AdjustmentType::MUT_REF,
+ e));
+ else
+ adjustments.push_back (
+ Resolver::Adjustment (Resolver::Adjustment::AdjustmentType::IMM_REF,
+ e));
+ }
+
+ auto resulting_dyn_object_ref
+ = ctx->get_backend ()->var_expression (dyn_tmp, locus);
+ for (auto it = adjustments.rbegin (); it != adjustments.rend (); it++)
+ {
+ bool ok
+ = it->get_type () == Resolver::Adjustment::AdjustmentType::IMM_REF
+ || it->get_type () == Resolver::Adjustment::AdjustmentType::MUT_REF;
+ rust_assert (ok);
+
+ resulting_dyn_object_ref
+ = ctx->get_backend ()->address_expression (resulting_dyn_object_ref,
+ locus);
+ }
+ return resulting_dyn_object_ref;
+}
+
+Bexpression *
+HIRCompileBase::compute_address_for_trait_item (
+ const Resolver::TraitItemReference *trait_item_ref, TyTy::BaseType *receiver)
+{
+ TyTy::BaseType *item_type = trait_item_ref->get_tyty ();
+ rust_assert (item_type->get_kind () == TyTy::TypeKind::FNDEF);
+ TyTy::FnType *fntype = static_cast<TyTy::FnType *> (item_type);
+
+ auto root = receiver->get_root ();
+ HIR::PathIdentSegment segment_name (trait_item_ref->get_identifier ());
+ std::vector<Resolver::PathProbeCandidate> candidates
+ = Resolver::PathProbeType::Probe (root, segment_name, true, false, true);
+
+ // FIXME for default trait item resolution
+ //
+ // if (candidates.size () == 0)
+ // {
+ // rust_assert (trait_item_ref->is_optional ()); // has definition
+ //
+ // CompileTraitItem::Compile (self_type,
+ // trait_item_ref->get_hir_trait_item (), ctx,
+ // fntype);
+ // if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &fn))
+ // {
+ // return ctx->get_backend ()->error_expression ();
+ // }
+ // }
+
+ rust_assert (!candidates.empty ());
+ rust_assert (candidates.size () == 1);
+
+ Resolver::PathProbeCandidate *candidate = &candidates.at (0);
+ rust_assert (candidate->is_impl_candidate ());
+
+ HIR::ImplItem *impl_item = candidate->item.impl.impl_item;
+
+ return CompileInherentImplItem::Compile (receiver->get_root (), impl_item,
+ ctx, true, fntype, true,
+ Location () /* FIXME */);
+}
+
} // namespace Compile
} // namespace Rust