summaryrefslogtreecommitdiff
path: root/src/mir
diff options
context:
space:
mode:
Diffstat (limited to 'src/mir')
-rw-r--r--src/mir/check.cpp4
-rw-r--r--src/mir/dump.cpp5
-rw-r--r--src/mir/from_hir.cpp74
-rw-r--r--src/mir/mir.cpp3
-rw-r--r--src/mir/mir.hpp4
-rw-r--r--src/mir/mir_builder.cpp9
6 files changed, 86 insertions, 13 deletions
diff --git a/src/mir/check.cpp b/src/mir/check.cpp
index 8c101041..89e75924 100644
--- a/src/mir/check.cpp
+++ b/src/mir/check.cpp
@@ -516,6 +516,10 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
// TODO: Ensure that the input type is a: Generic, Array, or DST
// TODO: Check return type
),
+ (DstPtr,
+ // TODO: Ensure that the input type is a DST
+ // TODO: Check return type
+ ),
(MakeDst,
),
(Tuple,
diff --git a/src/mir/dump.cpp b/src/mir/dump.cpp
index 967bc98d..da9d0ea9 100644
--- a/src/mir/dump.cpp
+++ b/src/mir/dump.cpp
@@ -353,6 +353,11 @@ namespace {
fmt_val(os, e.val);
os << ")";
),
+ (DstPtr,
+ os << "PTR(";
+ fmt_val(os, e.val);
+ os << ")";
+ ),
(MakeDst,
os << "DST(";
fmt_val(os, e.ptr_val);
diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp
index 1edf7903..7ded3cb4 100644
--- a/src/mir/from_hir.cpp
+++ b/src/mir/from_hir.cpp
@@ -1351,6 +1351,7 @@ namespace {
void visit(::HIR::ExprNode_CallPath& node) override
{
+ const Span& sp = node.span();
TRACE_FUNCTION_F("_CallPath " << node.m_path);
::std::vector< ::MIR::LValue> values;
values.reserve( node.m_args.size() );
@@ -1361,19 +1362,70 @@ namespace {
m_builder.moved_lvalue( arg->span(), values.back() );
}
- // TODO: Obtain function type for this function (i.e. a type that is specifically for this function)
- auto fcn_ty_data = ::HIR::FunctionType {
- false,
- "",
- box$( node.m_cache.m_arg_types.back().clone() ),
- {}
- };
- for(unsigned int i = 0; i < node.m_cache.m_arg_types.size() - 1; i ++)
+ ::MIR::LValue fcn_val;
+
+ // If the call was to a TraitObject function, get it from the vtable.
+ bool was_virtual = false;
+ if( node.m_path.m_data.is_UfcsKnown() && node.m_path.m_data.as_UfcsKnown().type->m_data.is_TraitObject() )
{
- fcn_ty_data.m_arg_types.push_back( node.m_cache.m_arg_types[i].clone() );
+ const auto& pe = node.m_path.m_data.as_UfcsKnown();
+ const auto& te = pe.type->m_data.as_TraitObject();
+ if( pe.trait == te.m_trait.m_path )
+ {
+ assert( te.m_trait.m_trait_ptr );
+ const auto& trait = *te.m_trait.m_trait_ptr;
+
+ // 1. Get the vtable index for this function
+ unsigned int vtable_idx = trait.m_values.at( pe.item ).vtable_ofs;
+ if( vtable_idx == ~0u ) {
+ BUG(sp, "Calling method '" << pe.item << "' of " << pe.trait << " which isn't in the vtable");
+ }
+
+ // 2. Load from the vtable
+ auto vtable_rval = ::MIR::RValue::make_DstMeta({
+ ::MIR::LValue::make_Deref({ box$(values.front().clone()) })
+ });
+ auto vtable_ty_spath = pe.trait.m_path;
+ vtable_ty_spath.m_components.back() += "#vtable";
+ const auto& vtable_ref = m_builder.crate().get_struct_by_path(sp, vtable_ty_spath);
+ // Copy the param set from the trait in the trait object
+ ::HIR::PathParams vtable_params = te.m_trait.m_path.m_params.clone();
+ // - Include associated types on bound
+ for(const auto& ty_b : te.m_trait.m_type_bounds) {
+ auto idx = trait.m_type_indexes.at(ty_b.first);
+ if(vtable_params.m_types.size() <= idx)
+ vtable_params.m_types.resize(idx+1);
+ vtable_params.m_types[idx] = ty_b.second.clone();
+ }
+ auto vtable_ty = ::HIR::TypeRef( ::HIR::GenericPath(vtable_ty_spath, mv$(vtable_params)), &vtable_ref );
+
+ auto vtable = m_builder.lvalue_or_temp(sp, mv$(vtable_ty), mv$(vtable_rval));
+ auto vtable_fcn = ::MIR::LValue::make_Field({ box$(vtable), vtable_idx });
+ m_builder.with_val_type(sp, vtable_fcn, [&](const auto& ty){
+ fcn_val = m_builder.new_temporary(ty);
+ });
+
+ m_builder.push_stmt_assign( sp, fcn_val.clone(), ::MIR::RValue( mv$(vtable_fcn) ) );
+ was_virtual = true;
+ }
+ }
+
+ if( ! was_virtual )
+ {
+ // TODO: Obtain function type for this function (i.e. a type that is specifically for this function)
+ auto fcn_ty_data = ::HIR::FunctionType {
+ false,
+ "",
+ box$( node.m_cache.m_arg_types.back().clone() ),
+ {}
+ };
+ for(unsigned int i = 0; i < node.m_cache.m_arg_types.size() - 1; i ++)
+ {
+ fcn_ty_data.m_arg_types.push_back( node.m_cache.m_arg_types[i].clone() );
+ }
+ fcn_val = m_builder.new_temporary( ::HIR::TypeRef(mv$(fcn_ty_data)) );
+ m_builder.push_stmt_assign( sp, fcn_val.clone(), ::MIR::RValue::make_Constant( ::MIR::Constant(node.m_path.clone()) ) );
}
- auto fcn_val = m_builder.new_temporary( ::HIR::TypeRef(mv$(fcn_ty_data)) );
- m_builder.push_stmt_assign( node.span(), fcn_val.clone(), ::MIR::RValue::make_Constant( ::MIR::Constant(node.m_path.clone()) ) );
auto panic_block = m_builder.new_bb_unlinked();
auto next_block = m_builder.new_bb_unlinked();
diff --git a/src/mir/mir.cpp b/src/mir/mir.cpp
index 0517111a..18c69a41 100644
--- a/src/mir/mir.cpp
+++ b/src/mir/mir.cpp
@@ -105,6 +105,9 @@ namespace MIR {
(DstMeta,
os << "DstMeta(" << e.val << ")";
),
+ (DstPtr,
+ os << "DstPtr(" << e.val << ")";
+ ),
(MakeDst,
os << "MakeDst(" << e.ptr_val << ", " << e.meta_val << ")";
),
diff --git a/src/mir/mir.hpp b/src/mir/mir.hpp
index c0ee0d21..bf5e2d4a 100644
--- a/src/mir/mir.hpp
+++ b/src/mir/mir.hpp
@@ -130,6 +130,10 @@ TAGGED_UNION(RValue, Use,
(DstMeta, struct {
LValue val;
}),
+ // Extract the pointer from a DST pointer (as *const ())
+ (DstPtr, struct {
+ LValue val;
+ }),
// Construct a DST pointer from a thin pointer and metadata
(MakeDst, struct {
LValue ptr_val;
diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp
index 202daac0..d539ef89 100644
--- a/src/mir/mir_builder.cpp
+++ b/src/mir/mir_builder.cpp
@@ -226,6 +226,9 @@ void MirBuilder::push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RVal
(DstMeta,
// Doesn't move
),
+ (DstPtr,
+ // Doesn't move
+ ),
(MakeDst,
// Doesn't move ptr_val
this->moved_lvalue(sp, e.meta_val);
@@ -741,7 +744,8 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::
BUG(sp, "Field on unit-like struct - " << ty);
),
(Tuple,
- ASSERT_BUG(sp, e.field_index < se.size(), "Field index out of range in tuple-struct");
+ ASSERT_BUG(sp, e.field_index < se.size(),
+ "Field index out of range in tuple-struct " << ty << " - " << e.field_index << " > " << se.size());
const auto& fld = se[e.field_index];
if( monomorphise_type_needed(fld.ent) ) {
auto sty = monomorphise_type(sp, str.m_params, te.path.m_data.as_Generic().m_params, fld.ent);
@@ -753,7 +757,8 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::
}
),
(Named,
- ASSERT_BUG(sp, e.field_index < se.size(), "Field index out of range in struct");
+ ASSERT_BUG(sp, e.field_index < se.size(),
+ "Field index out of range in struct " << ty << " - " << e.field_index << " > " << se.size());
const auto& fld = se[e.field_index].second;
if( monomorphise_type_needed(fld.ent) ) {
auto sty = monomorphise_type(sp, str.m_params, te.path.m_data.as_Generic().m_params, fld.ent);