diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/hir/deserialise.cpp | 11 | ||||
-rw-r--r-- | src/hir/hir.hpp | 20 | ||||
-rw-r--r-- | src/hir/serialise.cpp | 12 | ||||
-rw-r--r-- | src/hir_conv/markings.cpp | 80 | ||||
-rw-r--r-- | src/hir_typeck/expr_cs.cpp | 6 | ||||
-rw-r--r-- | src/mir/cleanup.cpp | 336 | ||||
-rw-r--r-- | src/mir/helpers.hpp | 6 |
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: |