summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/hir/deserialise.cpp11
-rw-r--r--src/hir/hir.hpp20
-rw-r--r--src/hir/serialise.cpp12
-rw-r--r--src/hir_conv/markings.cpp80
-rw-r--r--src/hir_typeck/expr_cs.cpp6
-rw-r--r--src/mir/cleanup.cpp336
-rw-r--r--src/mir/helpers.hpp6
7 files changed, 393 insertions, 78 deletions
diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp
index b7fa0a67..7d570b94 100644
--- a/src/hir/deserialise.cpp
+++ b/src/hir/deserialise.cpp
@@ -543,13 +543,12 @@ namespace {
::HIR::TraitMarkings m;
uint8_t bitflag_1 = m_in.read_u8();
#define BIT(i,fld) fld = (bitflag_1 & (1 << (i))) != 0;
- BIT(0, m.can_coerce)
- BIT(1, m.can_unsize)
- BIT(2, m.has_a_deref)
- BIT(3, m.is_always_unsized)
- BIT(4, m.is_always_sized)
- BIT(5, m.is_copy)
+ BIT(0, m.can_unsize)
+ BIT(1, m.has_a_deref)
+ BIT(2, m.is_copy)
#undef BIT
+ m.coerce_unsized_index = m_in.read_count( );
+ m.unsized_field = m_in.read_count( );
// TODO: auto_impls
return m;
}
diff --git a/src/hir/hir.hpp b/src/hir/hir.hpp
index ac1748c0..0d2330ed 100644
--- a/src/hir/hir.hpp
+++ b/src/hir/hir.hpp
@@ -133,18 +133,24 @@ typedef ::std::vector< ::std::pair< ::std::string, VisEnt<::HIR::TypeRef> > >
/// Cache of the state of various language traits on an enum/struct
struct TraitMarkings
{
- /// There is at least one CoerceUnsized impl for this type
- bool can_coerce = false;
- /// There is at least one CoerceUnsized impl for this type
+ /// There is at least one Unsize impl for this type
bool can_unsize = false;
/// Indicates that there is at least one Deref impl
bool has_a_deref = false;
- /// Type is always unsized (i.e. contains an unsized type)
- bool is_always_unsized = false;
- /// Type is always sized (i.e. cannot contain any unsized types)
- bool is_always_sized = false;
+ // If populated, indicates the field that is the coercable pointer.
+ unsigned int coerce_unsized_index = ~0u;
+
+ // TODO: This would have to be changed for custom DSTs
+ enum class DstType {
+ None, // Sized
+ Possible, // Has a ?Sized field
+ Slice, // [T]
+ TraitObject, // (Trait)
+ } dst_type;
+ unsigned int unsized_field = ~0u;
+
/// `true` if there is a Copy impl
bool is_copy = false;
diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp
index 65ccad6c..54b61387 100644
--- a/src/hir/serialise.cpp
+++ b/src/hir/serialise.cpp
@@ -804,14 +804,14 @@ namespace {
{
uint8_t bitflag_1 = 0;
#define BIT(i,fld) if(fld) bitflag_1 |= 1 << (i);
- BIT(0, m.can_coerce)
- BIT(1, m.can_unsize)
- BIT(2, m.has_a_deref)
- BIT(3, m.is_always_unsized)
- BIT(4, m.is_always_sized)
- BIT(5, m.is_copy)
+ BIT(0, m.can_unsize)
+ BIT(1, m.has_a_deref)
+ BIT(2, m.is_copy)
#undef BIT
m_out.write_u8(bitflag_1);
+
+ m_out.write_count( m.coerce_unsized_index );
+ m_out.write_count( m.unsized_field );
// TODO: auto_impls
}
diff --git a/src/hir_conv/markings.cpp b/src/hir_conv/markings.cpp
index 577ed63a..555b38bb 100644
--- a/src/hir_conv/markings.cpp
+++ b/src/hir_conv/markings.cpp
@@ -21,12 +21,14 @@ class Visitor:
const ::HIR::SimplePath& m_lang_Unsize;
const ::HIR::SimplePath& m_lang_CoerceUnsized;
const ::HIR::SimplePath& m_lang_Deref;
+ const ::HIR::SimplePath& m_lang_PhantomData;
public:
Visitor(const ::HIR::Crate& crate):
m_crate(crate),
m_lang_Unsize( crate.get_lang_item_path_opt("unsize") ),
m_lang_CoerceUnsized( crate.get_lang_item_path_opt("coerce_unsized") ),
- m_lang_Deref( crate.get_lang_item_path_opt("deref") )
+ m_lang_Deref( crate.get_lang_item_path_opt("deref") ),
+ m_lang_PhantomData( crate.get_lang_item_path_opt("phantom_data") )
{
}
@@ -58,10 +60,84 @@ public:
if( trait_path == m_lang_Unsize ) {
DEBUG("Type " << impl.m_type << " can Unsize");
markings.can_unsize = true;
+ // Determine which field is the one that does the unsize
}
else if( trait_path == m_lang_CoerceUnsized ) {
DEBUG("Type " << impl.m_type << " can Coerce");
- markings.can_coerce = true;
+ if( impl.m_trait_args.m_types.size() != 1 )
+ ERROR(sp, E0000, "Unexpected number of arguments for CoerceUnsized");
+ const auto& dst_ty = impl.m_trait_args.m_types[0];
+ // Determine which field is the one that does the coerce
+ if( !te.binding.is_Struct() )
+ ERROR(sp, E0000, "Cannot implement CoerceUnsized on non-structs");
+ if( !dst_ty.m_data.is_Path() )
+ ERROR(sp, E0000, "Cannot implement CoerceUnsized from non-structs");
+ const auto& dst_te = dst_ty.m_data.as_Path();
+ if( !dst_te.binding.is_Struct() )
+ ERROR(sp, E0000, "Cannot implement CoerceUnsized from non-structs");
+ if( dst_te.binding.as_Struct() != te.binding.as_Struct() )
+ ERROR(sp, E0000, "CoerceUnsized can only be implemented between variants of the same struct");
+
+ // NOTES: (from IRC: eddyb)
+ // < eddyb> they're required that T and U are the same struct definition (with different type parameters) and exactly one field differs in type between T and U (ignoring PhantomData)
+ // < eddyb> Mutabah: I forgot to mention that the field that differs in type must also impl CoerceUnsized
+
+ // Determine the difference in monomorphised variants.
+ unsigned int field = ~0u;
+ const auto& str = te.binding.as_Struct();
+
+ auto monomorph_cb_l = monomorphise_type_get_cb(sp, nullptr, &dst_te.path.m_data.as_Generic().m_params, nullptr);
+ auto monomorph_cb_r = monomorphise_type_get_cb(sp, nullptr, &te.path.m_data.as_Generic().m_params, nullptr);
+
+ TU_MATCHA( (str->m_data), (se),
+ (Unit,
+ ),
+ (Tuple,
+ for(unsigned int i = 0; i < se.size(); i ++)
+ {
+ // If the data is PhantomData, ignore it.
+ TU_IFLET(::HIR::TypeRef::Data, se[i].ent.m_data, Path, ite,
+ TU_IFLET(::HIR::Path::Data, ite.path.m_data, Generic, pe,
+ if( pe.m_path == m_lang_PhantomData )
+ continue ;
+ )
+ )
+ if( monomorphise_type_needed(se[i].ent) ) {
+ auto ty_l = monomorphise_type_with(sp, se[i].ent, monomorph_cb_l, false);
+ auto ty_r = monomorphise_type_with(sp, se[i].ent, monomorph_cb_r, false);
+ if( ty_l != ty_r ) {
+ if( field != ~0u )
+ ERROR(sp, E0000, "CoerceUnsized impls can only differ by one field");
+ field = i;
+ }
+ }
+ }
+ ),
+ (Named,
+ for(unsigned int i = 0; i < se.size(); i ++)
+ {
+ // If the data is PhantomData, ignore it.
+ TU_IFLET(::HIR::TypeRef::Data, se[i].second.ent.m_data, Path, ite,
+ TU_IFLET(::HIR::Path::Data, ite.path.m_data, Generic, pe,
+ if( pe.m_path == m_lang_PhantomData )
+ continue ;
+ )
+ )
+ if( monomorphise_type_needed(se[i].second.ent) ) {
+ auto ty_l = monomorphise_type_with(sp, se[i].second.ent, monomorph_cb_l, false);
+ auto ty_r = monomorphise_type_with(sp, se[i].second.ent, monomorph_cb_r, false);
+ if( ty_l != ty_r ) {
+ if( field != ~0u )
+ ERROR(sp, E0000, "CoerceUnsized impls can only differ by one field");
+ field = i;
+ }
+ }
+ }
+ )
+ )
+ if( field == ~0u )
+ ERROR(sp, E0000, "CoerceUnsized requires a field to differ between source and destination");
+ markings.coerce_unsized_index = field;
}
else if( trait_path == m_lang_Deref ) {
DEBUG("Type " << impl.m_type << " can Deref");
diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp
index 46fb2722..10d3f9fe 100644
--- a/src/hir_typeck/expr_cs.cpp
+++ b/src/hir_typeck/expr_cs.cpp
@@ -4389,13 +4389,13 @@ namespace {
return true;
),
(Struct,
- return pbe->m_markings.can_coerce;
+ return pbe->m_markings.coerce_unsized_index != ~0u;
),
(Union,
- return pbe->m_markings.can_coerce;
+ return pbe->m_markings.coerce_unsized_index != ~0u;
),
(Enum,
- return pbe->m_markings.can_coerce;
+ return pbe->m_markings.coerce_unsized_index != ~0u;
)
)
)
diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp
index 6393e6ca..88096704 100644
--- a/src/mir/cleanup.cpp
+++ b/src/mir/cleanup.cpp
@@ -15,6 +15,56 @@
#include <hir_typeck/static.hpp>
#include <mir/helpers.hpp>
+struct MirMutator
+{
+ ::MIR::Function& m_fcn;
+ unsigned int cur_block;
+ unsigned int cur_stmt;
+ mutable ::std::vector< ::MIR::Statement> new_statements;
+
+ MirMutator(::MIR::Function& fcn, unsigned int bb, unsigned int stmt):
+ m_fcn(fcn),
+ cur_block(bb), cur_stmt(stmt)
+ {
+ }
+
+ ::MIR::LValue new_temporary(::HIR::TypeRef ty)
+ {
+ auto rv = ::MIR::LValue::make_Temporary({ static_cast<unsigned int>(m_fcn.temporaries.size()) });
+ m_fcn.temporaries.push_back( mv$(ty) );
+ return rv;
+ }
+
+ void push_statement(::MIR::Statement stmt)
+ {
+ new_statements.push_back( mv$(stmt) );
+ }
+
+ ::MIR::LValue in_temporary(::HIR::TypeRef ty, ::MIR::RValue val)
+ {
+ auto rv = this->new_temporary( mv$(ty) );
+ push_statement( ::MIR::Statement::make_Assign({ rv.clone(), mv$(val) }) );
+ return rv;
+ }
+
+ decltype(new_statements.begin()) flush()
+ {
+ DEBUG("flush - " << cur_block << "/" << cur_stmt);
+ auto& block = m_fcn.blocks.at(cur_block);
+ assert( cur_stmt <= block.statements.size() );
+ auto it = block.statements.begin() + cur_stmt;
+ for(auto& stmt : new_statements)
+ {
+ DEBUG("- Push stmt @" << cur_stmt << " (size=" << block.statements.size() + 1 << ")");
+ it = block.statements.insert(it, mv$(stmt));
+ ++ it;
+ cur_stmt += 1;
+ }
+ new_statements.clear();
+ return it;
+ }
+};
+
const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::Path& path, ::HIR::TypeRef& out_ty)
{
TU_MATCHA( (path.m_data), (pe),
@@ -36,8 +86,8 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR
}
::MIR::LValue MIR_Cleanup_Virtualize(
- const Span& sp, const ::MIR::TypeResolve& state, ::MIR::Function& fcn,
- ::MIR::BasicBlock& block, ::MIR::LValue& receiver_lvp,
+ const Span& sp, const ::MIR::TypeResolve& state, MirMutator& mutator,
+ ::MIR::LValue& receiver_lvp,
const ::HIR::TypeRef::Data::Data_TraitObject& te, const ::HIR::Path::Data::Data_UfcsKnown& pe
)
{
@@ -79,39 +129,221 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR
);
// Allocate a temporary for the vtable pointer itself
- auto vtable_lv = ::MIR::LValue::make_Temporary({ static_cast<unsigned int>(fcn.temporaries.size()) });
- fcn.temporaries.push_back( mv$(vtable_ty) );
+ auto vtable_lv = mutator.new_temporary( mv$(vtable_ty) );
// - Load the vtable and store it
auto vtable_rval = ::MIR::RValue::make_DstMeta({ ::MIR::LValue::make_Deref({ box$(receiver_lvp.clone()) }) });
- block.statements.push_back( ::MIR::Statement::make_Assign({ vtable_lv.clone(), mv$(vtable_rval) }) );
+ mutator.push_statement( ::MIR::Statement::make_Assign({ vtable_lv.clone(), mv$(vtable_rval) }) );
auto ptr_rval = ::MIR::RValue::make_DstPtr({ ::MIR::LValue::make_Deref({ box$(receiver_lvp.clone()) }) });
- auto ptr_lv = ::MIR::LValue::make_Temporary({ static_cast<unsigned int>(fcn.temporaries.size()) });
- fcn.temporaries.push_back( ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Shared, ::HIR::TypeRef::new_unit()) );
- block.statements.push_back( ::MIR::Statement::make_Assign({ ptr_lv.clone(), mv$(ptr_rval) }) );
+ auto ptr_lv = mutator.new_temporary( ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Shared, ::HIR::TypeRef::new_unit()) );
+ mutator.push_statement( ::MIR::Statement::make_Assign({ ptr_lv.clone(), mv$(ptr_rval) }) );
receiver_lvp = mv$(ptr_lv);
// Update the terminator with the new information.
return ::MIR::LValue::make_Field({ box$(::MIR::LValue::make_Deref({ box$(vtable_lv) })), vtable_idx });
}
+::MIR::RValue MIR_Cleanup_Unsize(const ::MIR::TypeResolve& state, MirMutator& mutator, const ::HIR::TypeRef& dst_ty, const ::HIR::TypeRef& src_ty_inner, ::MIR::LValue ptr_value)
+{
+ const auto& dst_ty_inner = (dst_ty.m_data.is_Borrow() ? *dst_ty.m_data.as_Borrow().inner : *dst_ty.m_data.as_Pointer().inner);
+
+ TU_MATCH_DEF( ::HIR::TypeRef::Data, (dst_ty_inner.m_data), (die),
+ (
+ // Dunno?
+ MIR_TODO(state, "Unsize to pointer to " << dst_ty_inner);
+ ),
+ (Generic,
+ // Emit a cast rvalue
+ return ::MIR::RValue::make_Cast({ mv$(ptr_value), dst_ty.clone() });
+ ),
+ (Slice,
+ if( src_ty_inner.m_data.is_Array() )
+ {
+ const auto& in_array = src_ty_inner.m_data.as_Array();
+ auto size_lval = mutator.in_temporary( ::HIR::TypeRef(::HIR::CoreType::Usize), ::MIR::Constant( static_cast<uint64_t>(in_array.size_val) ) );
+ return ::MIR::RValue::make_MakeDst({ mv$(ptr_value), mv$(size_lval) });
+ }
+ else if( src_ty_inner.m_data.is_Generic() || (src_ty_inner.m_data.is_Path() && src_ty_inner.m_data.as_Path().binding.is_Opaque()) )
+ {
+ // HACK: FixedSizeArray uses `A: Unsize<[T]>` which will lead to the above code not working (as the size isn't known).
+ // - Maybe _Meta on the `&A` would work as a stopgap (since A: Sized, it won't collide with &[T] or similar)
+ auto size_lval = mutator.in_temporary( ::HIR::TypeRef(::HIR::CoreType::Usize), ::MIR::RValue::make_DstMeta({ ptr_value.clone() }) );
+ return ::MIR::RValue::make_MakeDst({ mv$(ptr_value), mv$(size_lval) });
+ }
+ else
+ {
+ MIR_BUG(state, "Unsize to slice from non-array - " << src_ty_inner);
+ }
+ ),
+ (TraitObject,
+ auto unit_ptr = ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Shared, ::HIR::TypeRef::new_unit());
+ // If the data trait hasn't changed, re-create the DST
+ if( src_ty_inner.m_data.is_TraitObject() )
+ {
+ auto inner_ptr_lval = mutator.in_temporary( unit_ptr.clone(), ::MIR::RValue::make_DstPtr({ ptr_value.clone() }) );
+ auto vtable_lval = mutator.in_temporary( unit_ptr.clone(), ::MIR::RValue::make_DstMeta({ ptr_value.clone() }) );
+ return ::MIR::RValue::make_MakeDst({ mv$(inner_ptr_lval), mv$(vtable_lval) });
+ }
+ else
+ {
+ // Obtain the vtable if the destination is a trait object vtable exists as an unnamable associated type
+ ::MIR::LValue vtable_lval;
+ if( die.m_trait.m_path.m_path == ::HIR::SimplePath() )
+ {
+ auto null_lval = mutator.in_temporary( ::HIR::CoreType::Usize, ::MIR::Constant::make_Uint(0u) );
+ auto unit_ptr_2 = unit_ptr.clone();
+ vtable_lval = mutator.in_temporary( mv$(unit_ptr), ::MIR::RValue::make_Cast({ mv$(null_lval), mv$(unit_ptr_2) }) );
+ }
+ else
+ {
+ const auto& trait = *die.m_trait.m_trait_ptr;
+
+ auto vtable_ty_spath = die.m_trait.m_path.m_path;
+ vtable_ty_spath.m_components.back() += "#vtable";
+ const auto& vtable_ref = state.m_crate.get_struct_by_path(state.sp, vtable_ty_spath);
+ // Copy the param set from the trait in the trait object
+ ::HIR::PathParams vtable_params = die.m_trait.m_path.m_params.clone();
+ // - Include associated types on bound
+ for(const auto& ty_b : die.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_type = ::HIR::TypeRef( ::HIR::GenericPath(vtable_ty_spath, mv$(vtable_params)), &vtable_ref );
+
+ ::HIR::Path vtable { src_ty_inner.clone(), die.m_trait.m_path.clone(), "#vtable" };
+ vtable_lval = mutator.in_temporary(
+ ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Shared, mv$(vtable_type)),
+ ::MIR::RValue( ::MIR::Constant::make_ItemAddr(mv$(vtable)) )
+ );
+
+ }
+ return ::MIR::RValue::make_MakeDst({ mv$(ptr_value), mv$(vtable_lval) });
+ }
+ )
+ )
+}
+
+::MIR::RValue MIR_Cleanup_CoerceUnsized(const ::MIR::TypeResolve& state, MirMutator& mutator, const ::HIR::TypeRef& dst_ty, const ::HIR::TypeRef& src_ty, ::MIR::LValue value)
+{
+ // > Path -> Path = Unsize
+ // (path being destination is otherwise invalid)
+ if( dst_ty.m_data.is_Path() )
+ {
+ MIR_ASSERT(state, src_ty.m_data.is_Path(), "CoerceUnsized to Path must have a Path source - " << src_ty << " to " << dst_ty);
+ const auto& dte = dst_ty.m_data.as_Path();
+ const auto& ste = src_ty.m_data.as_Path();
+
+ // - Types must differ only by a single field, and be from the same definition
+ MIR_ASSERT(state, dte.binding.is_Struct(), "Note, can't CoerceUnsized non-structs");
+ MIR_ASSERT(state, dte.binding.tag() == ste.binding.tag(),
+ "Note, can't CoerceUnsized mismatched structs - " << src_ty << " to " << dst_ty);
+ MIR_ASSERT(state, dte.binding.as_Struct() == ste.binding.as_Struct(),
+ "Note, can't CoerceUnsized mismatched structs - " << src_ty << " to " << dst_ty);
+ const auto& str = *dte.binding.as_Struct();
+ MIR_ASSERT(state, str.m_markings.coerce_unsized_index != ~0u,
+ "Struct " << src_ty << " doesn't impl CoerceUnsized");
+
+ auto monomorph_cb_d = monomorphise_type_get_cb(state.sp, nullptr, &dte.path.m_data.as_Generic().m_params, nullptr);
+ auto monomorph_cb_s = monomorphise_type_get_cb(state.sp, nullptr, &ste.path.m_data.as_Generic().m_params, nullptr);
+
+ // - Destructure and restrucure with the unsized fields
+ ::std::vector<::MIR::LValue> ents;
+ TU_MATCHA( (str.m_data), (se),
+ (Unit,
+ MIR_BUG(state, "Unit-like struct CoerceUnsized is impossible - " << src_ty);
+ ),
+ (Tuple,
+ ents.reserve( se.size() );
+ for(unsigned int i = 0; i < se.size(); i++)
+ {
+ if( i == str.m_markings.coerce_unsized_index )
+ {
+ auto ty_d = monomorphise_type_with(state.sp, se[i].ent, monomorph_cb_d, false);
+ auto ty_s = monomorphise_type_with(state.sp, se[i].ent, monomorph_cb_s, false);
+
+ auto new_rval = MIR_Cleanup_CoerceUnsized(state, mutator, ty_d, ty_s, ::MIR::LValue::make_Field({ box$(value.clone()), i }));
+ auto new_lval = mutator.new_temporary( mv$(ty_d) );
+ mutator.push_statement( ::MIR::Statement::make_Assign({ new_lval.clone(), mv$(new_rval) }) );
+
+ ents.push_back( mv$(new_lval) );
+ }
+ else
+ {
+ ents.push_back( ::MIR::LValue::make_Field({ box$(value.clone()), i}) );
+ }
+ }
+ ),
+ (Named,
+ ents.reserve( se.size() );
+ for(unsigned int i = 0; i < se.size(); i++)
+ {
+ if( i == str.m_markings.coerce_unsized_index ) {
+ auto ty_d = monomorphise_type_with(state.sp, se[i].second.ent, monomorph_cb_d, false);
+ auto ty_s = monomorphise_type_with(state.sp, se[i].second.ent, monomorph_cb_s, false);
+
+ auto new_rval = MIR_Cleanup_CoerceUnsized(state, mutator, ty_d, ty_s, ::MIR::LValue::make_Field({ box$(value.clone()), i }));
+ auto new_lval = mutator.new_temporary( mv$(ty_d) );
+ mutator.push_statement( ::MIR::Statement::make_Assign({ new_lval.clone(), mv$(new_rval) }) );
+
+ ents.push_back( mv$(new_lval) );
+ }
+ else {
+ ents.push_back( ::MIR::LValue::make_Field({ box$(value.clone()), i}) );
+ }
+ }
+ )
+ )
+ return ::MIR::RValue::make_Struct({ dte.path.m_data.as_Generic().clone(), ~0u, mv$(ents) });
+ }
+
+ if( dst_ty.m_data.is_Borrow() )
+ {
+ MIR_ASSERT(state, src_ty.m_data.is_Borrow(), "CoerceUnsized to Borrow must have a Borrow source - " << src_ty << " to " << dst_ty);
+ const auto& ste = src_ty.m_data.as_Borrow();
+
+ return MIR_Cleanup_Unsize(state, mutator, dst_ty, *ste.inner, mv$(value));
+ }
+
+ // Pointer Coercion - Downcast and unsize
+ if( dst_ty.m_data.is_Pointer() )
+ {
+ MIR_ASSERT(state, src_ty.m_data.is_Pointer(), "CoerceUnsized to Pointer must have a Pointer source - " << src_ty << " to " << dst_ty);
+ const auto& dte = dst_ty.m_data.as_Pointer();
+ const auto& ste = src_ty.m_data.as_Pointer();
+
+ if( dte.type == ste.type )
+ {
+ // TODO: Use unsize code above
+ return MIR_Cleanup_Unsize(state, mutator, dst_ty, *ste.inner, mv$(value));
+ }
+ else
+ {
+ MIR_ASSERT(state, *dte.inner == *ste.inner, "TODO: Can pointer CoerceUnsized unsize? " << src_ty << " to " << dst_ty);
+ MIR_ASSERT(state, dte.type < ste.type, "CoerceUnsize attempting to raise pointer type");
+
+ return ::MIR::RValue::make_Cast({ mv$(value), dst_ty.clone() });
+ }
+ }
+
+ MIR_BUG(state, "Unknown CoerceUnsized target " << dst_ty << " from " << src_ty);
+ throw "";
+}
+
void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ::MIR::Function& fcn, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_type)
{
Span sp;
::MIR::TypeResolve state { sp, resolve, FMT_CB(ss, ss << path;), ret_type, args, fcn };
+ MirMutator mutator { fcn, 0, 0 };
for(auto& block : fcn.blocks)
{
for(auto it = block.statements.begin(); it != block.statements.end(); ++ it)
{
+ state.set_cur_stmt( mutator.cur_block, mutator.cur_stmt );
auto& stmt = *it;
- ::std::vector< ::MIR::Statement> new_stmts;
- auto new_temporary = [&](::HIR::TypeRef ty, ::MIR::RValue val)->::MIR::LValue {
- auto rv = ::MIR::LValue::make_Temporary({ static_cast<unsigned int>(fcn.temporaries.size()) });
- fcn.temporaries.push_back( mv$(ty) );
- new_stmts.push_back( ::MIR::Statement::make_Assign({ rv.clone(), mv$(val) }) );
- return rv;
- };
+
if( stmt.is_Assign() )
{
auto& se = stmt.as_Assign();
@@ -162,7 +394,7 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path,
// TODO:
}
else {
- auto lval = new_temporary( ::HIR::CoreType::Usize, ::MIR::RValue( ::MIR::Constant::make_Uint( lit_ptr->as_Integer() ) ) );
+ auto lval = mutator.in_temporary( ::HIR::CoreType::Usize, ::MIR::RValue( ::MIR::Constant::make_Uint( lit_ptr->as_Integer() ) ) );
se.src = ::MIR::RValue::make_Cast({ mv$(lval), mv$(ty) });
}
),
@@ -193,50 +425,48 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path,
)
}
)
-
- if( se.src.is_Cast() )
- {
- const auto& e = se.src.as_Cast();
- ::HIR::TypeRef tmp;
- const auto& src_ty = state.get_lvalue_type(tmp, e.val);
- // TODO: Unsize and CoerceUnsized operations
- // - Unsize should create a fat pointer if the pointer class is known (vtable or len)
- TU_IFLET( ::HIR::TypeRef::Data, e.type.m_data, Borrow, te
- // > & -> & = Unsize, create DST based on the pointer class of the destination.
- // (&-ptr being destination is otherwise invalid)
- // TODO Share with the CoerceUnsized handling
- )
- // - CoerceUnsized should re-create the inner type if known.
- else TU_IFLET( ::HIR::TypeRef::Data, e.type.m_data, Path, te,
- TU_IFLET( ::HIR::TypeRef::Data, src_ty.m_data, Path, ste,
- // > Path -> Path = Unsize
- // (path being destination is otherwise invalid)
- ASSERT_BUG( sp, ! te.binding.is_Unbound(), "" );
- ASSERT_BUG( sp, !ste.binding.is_Unbound(), "" );
- if( te.binding.is_Opaque() || ste.binding.is_Opaque() ) {
- }
- else {
- // - Types must differ only by a single field, and be from the same definition
- ASSERT_BUG(sp, te.binding.tag() == ste.binding.tag(), "" );
- // TODO: The CoerceUnsized rule could be in the TraitMarkings (listing the relevant field)
- // - Destructure and restrucure with the unsized fields
- }
- )
+ )
+
+ if( se.src.is_Cast() )
+ {
+ auto& e = se.src.as_Cast();
+ ::HIR::TypeRef tmp;
+ const auto& src_ty = state.get_lvalue_type(tmp, e.val);
+ // TODO: Unsize and CoerceUnsized operations
+ // - Unsize should create a fat pointer if the pointer class is known (vtable or len)
+ TU_IFLET( ::HIR::TypeRef::Data, e.type.m_data, Borrow, te
+ // > & -> & = Unsize, create DST based on the pointer class of the destination.
+ // (&-ptr being destination is otherwise invalid)
+ // TODO Share with the CoerceUnsized handling?
+ )
+ // - CoerceUnsized should re-create the inner type if known.
+ else TU_IFLET( ::HIR::TypeRef::Data, e.type.m_data, Path, te,
+ TU_IFLET( ::HIR::TypeRef::Data, src_ty.m_data, Path, ste,
+ ASSERT_BUG( sp, ! te.binding.is_Unbound(), "" );
+ ASSERT_BUG( sp, !ste.binding.is_Unbound(), "" );
+ if( te.binding.is_Opaque() || ste.binding.is_Opaque() ) {
+ // Either side is opaque, leave for now
+ }
else {
- ASSERT_BUG( sp, src_ty.m_data.is_Generic(), "Cast to Path from " << src_ty );
+ se.src = MIR_Cleanup_CoerceUnsized(state, mutator, e.type, src_ty, mv$(e.val));
}
)
else {
+ ASSERT_BUG( sp, src_ty.m_data.is_Generic(), "Cast to Path from " << src_ty );
}
+ )
+ else {
}
- )
+ }
}
- for(auto& v : new_stmts) {
- it = block.statements.insert(it, mv$(v));
- }
+ DEBUG(it - block.statements.begin());
+ it = mutator.flush();
+ DEBUG(it - block.statements.begin());
+ mutator.cur_stmt += 1;
}
+ state.set_cur_stmt_term( mutator.cur_block );
TU_IFLET( ::MIR::Terminator, block.terminator, Call, e,
TU_IFLET( ::MIR::CallTarget, e.fcn, Path, path,
@@ -255,12 +485,16 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path,
)
)
{
- auto tgt_lvalue = MIR_Cleanup_Virtualize(sp, state, fcn, block, e.args.front(), te, pe);
+ auto tgt_lvalue = MIR_Cleanup_Virtualize(sp, state, mutator, e.args.front(), te, pe);
e.fcn = mv$(tgt_lvalue);
}
}
)
)
+
+ mutator.flush();
+ mutator.cur_block += 1;
+ mutator.cur_stmt = 0;
}
}
diff --git a/src/mir/helpers.hpp b/src/mir/helpers.hpp
index 2a4f81d5..aef012a7 100644
--- a/src/mir/helpers.hpp
+++ b/src/mir/helpers.hpp
@@ -27,9 +27,9 @@ struct CheckFailure:
{
};
-#define MIR_BUG(state, ...) ( (state).print_bug( [&](auto& _os){_os << __VA_ARGS__; } ) )
+#define MIR_BUG(state, ...) do { (state).print_bug( [&](auto& _os){_os << __VA_ARGS__; } ); throw ""; } while(0)
#define MIR_ASSERT(state, cnd, ...) do { if( !(cnd) ) (state).print_bug( [&](auto& _os){_os << "ASSERT " #cnd " failed - " << __VA_ARGS__; } ); } while(0)
-#define MIR_TODO(state, ...) ( (state).print_todo( [&](auto& _os){_os << __VA_ARGS__; } ) )
+#define MIR_TODO(state, ...) do { (state).print_todo( [&](auto& _os){_os << __VA_ARGS__; } ); throw ""; } while(0)
class TypeResolve
{
@@ -38,8 +38,8 @@ public:
private:
const unsigned int STMT_TERM = ~0u;
- const Span& sp;
public:
+ const Span& sp;
const ::StaticTraitResolve& m_resolve;
const ::HIR::Crate& m_crate;
private: