diff options
author | John Hodge <tpg@ucc.asn.au> | 2017-11-26 18:28:08 +0800 |
---|---|---|
committer | John Hodge <tpg@ucc.asn.au> | 2017-11-26 18:28:08 +0800 |
commit | ad4d5ab92a8317428e066b70977333be106abaa0 (patch) | |
tree | 1d6f34f219d2f77fb5c85526f9bc6a23bb8e9604 | |
parent | e335207c353efec94963e273d2fc3294afc860e0 (diff) | |
download | mrust-ad4d5ab92a8317428e066b70977333be106abaa0.tar.gz |
HIR/MIR - Error checking for assigning into ! (as opposed to from !)
-rw-r--r-- | src/hir_typeck/expr_check.cpp | 31 | ||||
-rw-r--r-- | src/hir_typeck/expr_cs.cpp | 4 | ||||
-rw-r--r-- | src/mir/check.cpp | 44 | ||||
-rw-r--r-- | src/mir/from_hir.cpp | 7 | ||||
-rw-r--r-- | src/mir/from_hir.hpp | 3 | ||||
-rw-r--r-- | src/mir/mir_builder.cpp | 26 |
6 files changed, 86 insertions, 29 deletions
diff --git a/src/hir_typeck/expr_check.cpp b/src/hir_typeck/expr_check.cpp index febe8190..985fe15f 100644 --- a/src/hir_typeck/expr_check.cpp +++ b/src/hir_typeck/expr_check.cpp @@ -21,6 +21,7 @@ namespace { //const t_args& m_args; const ::HIR::TypeRef& ret_type; ::std::vector< const ::HIR::TypeRef*> closure_ret_types; + ::std::vector<const ::HIR::ExprNode_Loop*> m_loops; ::HIR::SimplePath m_lang_Index; @@ -93,11 +94,37 @@ namespace { void visit(::HIR::ExprNode_Loop& node) override { TRACE_FUNCTION_F(&node << " loop { ... }"); + m_loops.push_back(&node); node.m_code->visit(*this); + m_loops.pop_back(); } void visit(::HIR::ExprNode_LoopControl& node) override { - //TRACE_FUNCTION_F(&node << " " << (node.m_continue ? "continue" : "break") << " '" << node.m_label); + TRACE_FUNCTION_F(&node << " " << (node.m_continue ? "continue" : "break") << " '" << node.m_label); + // TODO: Validate `break` return value + if( node.m_value ) + { + node.m_value->visit(*this); + } + + if( !node.m_continue ) + { + ::HIR::TypeRef unit = ::HIR::TypeRef::new_unit(); + const auto& ty = (node.m_value ? node.m_value->m_res_type : unit); + const ::HIR::ExprNode_Loop* loop; + if( node.m_label == "" ) { + ASSERT_BUG(node.span(), !m_loops.empty(), "Break with no loop"); + loop = m_loops.back(); + } + else { + auto it = ::std::find_if( m_loops.rbegin(), m_loops.rend(), [&](const auto* lp){ return lp->m_label == node.m_label; } ); + ASSERT_BUG(node.span(), it != m_loops.rend(), "Break with no matching loop"); + loop = *it; + } + + DEBUG("Breaking to " << loop << ", type " << loop->m_res_type); + check_types_equal(node.span(), loop->m_res_type, ty); + } } void visit(::HIR::ExprNode_Let& node) override { @@ -1023,7 +1050,7 @@ namespace { } void check_types_equal(const Span& sp, const ::HIR::TypeRef& l, const ::HIR::TypeRef& r) const { - if( l.m_data.is_Diverge() || r.m_data.is_Diverge() ) { + if( /*l.m_data.is_Diverge() ||*/ r.m_data.is_Diverge() ) { // Diverge, matches everything. // TODO: Is this always true? } diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index d3587095..ab69bbc6 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -3311,12 +3311,12 @@ void Context::equate_types_inner(const Span& sp, const ::HIR::TypeRef& li, const if( l_t.m_data.is_Diverge() && r_t.m_data.is_Diverge() ) { return ; } - else if( l_t.m_data.is_Diverge() ) { + /*else if( l_t.m_data.is_Diverge() ) { TU_IFLET(::HIR::TypeRef::Data, li.m_data, Infer, l_e, this->m_ivars.set_ivar_to(l_e.index, r_t.clone()); ) return ; - } + }*/ else if( r_t.m_data.is_Diverge() ) { TU_IFLET(::HIR::TypeRef::Data, ri.m_data, Infer, r_e, this->m_ivars.set_ivar_to(r_e.index, l_t.clone()); diff --git a/src/mir/check.cpp b/src/mir/check.cpp index d17cb660..17c77cd5 100644 --- a/src/mir/check.cpp +++ b/src/mir/check.cpp @@ -563,6 +563,7 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path // [Flat] = Basic checks (just iterates BBs) // - [Flat] Types must be valid (correct type for slot etc.) // - Simple check of all assignments/calls/... + DEBUG("=== FLAT CHECKS"); { for(unsigned int bb_idx = 0; bb_idx < fcn.blocks.size(); bb_idx ++) { @@ -571,6 +572,7 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path { const auto& stmt = bb.statements[stmt_idx]; state.set_cur_stmt(bb_idx, stmt_idx); + DEBUG(state << stmt); switch( stmt.tag() ) { @@ -580,13 +582,15 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path break; case ::MIR::Statement::TAG_Assign: { const auto& a = stmt.as_Assign(); + ::HIR::TypeRef dst_tmp; + const auto& dst_ty = state.get_lvalue_type(dst_tmp, a.dst); - auto check_type = [&](const auto& src_ty) { - ::HIR::TypeRef tmp; - const auto& dst_ty = state.get_lvalue_type(tmp, a.dst); + auto check_types = [&](const auto& dst_ty, const auto& src_ty) { if( src_ty == ::HIR::TypeRef::new_diverge() ) { + // It's valid to assign to anything from a ! } else if( src_ty == dst_ty ) { + // Types are equal, good. } else { MIR_BUG(state, "Type mismatch, destination is " << dst_ty << ", source is " << src_ty); @@ -595,12 +599,10 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path TU_MATCH(::MIR::RValue, (a.src), (e), (Use, ::HIR::TypeRef tmp; - check_type( state.get_lvalue_type(tmp, e) ); + check_types( dst_ty, state.get_lvalue_type(tmp, e) ); ), (Constant, // TODO: Check constant types. - ::HIR::TypeRef tmp; - const auto& dst_ty = state.get_lvalue_type(tmp, a.dst); TU_MATCH( ::MIR::Constant, (e), (c), (Int, bool good = false; @@ -660,13 +662,13 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path } ), (Bool, - check_type( ::HIR::TypeRef(::HIR::CoreType::Bool) ); + check_types( dst_ty, ::HIR::TypeRef(::HIR::CoreType::Bool) ); ), (Bytes, - check_type( ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ::HIR::TypeRef::new_array(::HIR::CoreType::U8, c.size())) ); + check_types( dst_ty, ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ::HIR::TypeRef::new_array(::HIR::CoreType::U8, c.size())) ); ), (StaticString, - check_type( ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ::HIR::CoreType::Str) ); + check_types( dst_ty, ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ::HIR::CoreType::Str) ); ), (Const, // TODO: Check result type against type of const @@ -775,26 +777,35 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path // TODO: Check return type ), (MakeDst, - ::HIR::TypeRef tmp; - const auto& ty = state.get_lvalue_type(tmp, a.dst); const ::HIR::TypeRef* ity_p = nullptr; - if( const auto* te = ty.m_data.opt_Borrow() ) + if( const auto* te = dst_ty.m_data.opt_Borrow() ) ity_p = &*te->inner; - else if( const auto* te = ty.m_data.opt_Pointer() ) + else if( const auto* te = dst_ty.m_data.opt_Pointer() ) ity_p = &*te->inner; else { - MIR_BUG(state, "DstMeta requires a pointer as output, got " << ty); + MIR_BUG(state, "DstMeta requires a pointer as output, got " << dst_ty); } assert(ity_p); auto meta = get_metadata_type(state, *ity_p); if( meta == ::HIR::TypeRef() ) { - MIR_BUG(state, "DstMeta requires a pointer to an unsized type as output, got " << ty); + MIR_BUG(state, "DstMeta requires a pointer to an unsized type as output, got " << dst_ty); } // TODO: Check metadata type? + + // NOTE: Output type checked above. ), (Tuple, - // TODO: Check return type + if( !dst_ty.m_data.is_Tuple() ) + MIR_BUG(state, "Tuple assigned slot of invalid type, " << dst_ty); + const auto& dst_itys = dst_ty.m_data.as_Tuple(); + if( dst_itys.size() != e.vals.size() ) + MIR_BUG(state, "Tuple assigned slot of invalid type, " << dst_ty << " - expected " << e.vals.size() << " elements"); + for(size_t i = 0; i < e.vals.size(); i++) + { + ::HIR::TypeRef tmp2; + check_types( dst_itys[i], state.get_param_type(tmp2, e.vals[i]) ); + } ), (Array, // TODO: Check return type @@ -820,6 +831,7 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path } state.set_cur_stmt_term(bb_idx); + DEBUG(state << bb.terminator); TU_MATCH(::MIR::Terminator, (bb.terminator), (e), (Incomplete, ), diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index 74d6af9c..a6af0450 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -441,6 +441,7 @@ namespace { // TODO: Emit a drop m_builder.get_result(sp); m_builder.terminate_scope(sp, mv$(stmt_scope)); + diverged |= subnode->m_res_type.m_data.is_Diverge(); } else { m_builder.terminate_scope(sp, mv$(stmt_scope), false); @@ -2360,7 +2361,7 @@ namespace { } -::MIR::FunctionPointer LowerMIR(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, const ::HIR::ExprPtr& ptr, const ::HIR::Function::args_t& args) +::MIR::FunctionPointer LowerMIR(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, const ::HIR::ExprPtr& ptr, const ::HIR::TypeRef& ret_ty, const ::HIR::Function::args_t& args) { TRACE_FUNCTION; @@ -2371,7 +2372,7 @@ namespace { // Scope ensures that builder cleanup happens before `fcn` is moved { - MirBuilder builder { ptr->span(), resolve, args, fcn }; + MirBuilder builder { ptr->span(), resolve, ret_ty, args, fcn }; ExprVisitor_Conv ev { builder, ptr.m_bindings }; // 1. Apply destructuring to arguments @@ -2411,7 +2412,7 @@ namespace { void HIR_GenerateMIR(::HIR::Crate& crate) { ::MIR::OuterVisitor ov { crate, [&](const auto& res, const auto& p, auto& expr_ptr, const auto& args, const auto& ty){ - expr_ptr.m_mir = LowerMIR(res, p, expr_ptr, args); + expr_ptr.m_mir = LowerMIR(res, p, expr_ptr, ty, args); } }; ov.visit_crate(crate); } diff --git a/src/mir/from_hir.hpp b/src/mir/from_hir.hpp index 79e71196..0dcbd65b 100644 --- a/src/mir/from_hir.hpp +++ b/src/mir/from_hir.hpp @@ -130,6 +130,7 @@ class MirBuilder const Span& m_root_span; const StaticTraitResolve& m_resolve; + const ::HIR::TypeRef& m_ret_ty; const ::HIR::Function::args_t& m_args; ::MIR::Function& m_output; @@ -175,7 +176,7 @@ class MirBuilder // the optimiser. ::MIR::LValue m_if_cond_lval; public: - MirBuilder(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::Function::args_t& args, ::MIR::Function& output); + MirBuilder(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ret_ty, const ::HIR::Function::args_t& args, ::MIR::Function& output); ~MirBuilder(); const ::HIR::SimplePath* lang_Box() const { return m_lang_Box; } diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp index 93c4a10d..f2b3a246 100644 --- a/src/mir/mir_builder.cpp +++ b/src/mir/mir_builder.cpp @@ -11,9 +11,10 @@ // -------------------------------------------------------------------- // MirBuilder // -------------------------------------------------------------------- -MirBuilder::MirBuilder(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::Function::args_t& args, ::MIR::Function& output): +MirBuilder::MirBuilder(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ret_ty, const ::HIR::Function::args_t& args, ::MIR::Function& output): m_root_span(sp), m_resolve(resolve), + m_ret_ty(ret_ty), m_args(args), m_output(output), m_lang_Box(nullptr), @@ -56,14 +57,29 @@ MirBuilder::~MirBuilder() const auto& sp = m_root_span; if( block_active() ) { - if( has_result() ) + if( m_ret_ty.m_data.is_Diverge() ) { - push_stmt_assign( sp, ::MIR::LValue::make_Return({}), get_result(sp) ); + terminate_scope_early(sp, fcn_scope()); + // Validation fails if this is reachable. + //end_block( ::MIR::Terminator::make_Incomplete({}) ); + end_block( ::MIR::Terminator::make_Diverge({}) ); } + else + { + if( has_result() ) + { + push_stmt_assign( sp, ::MIR::LValue::make_Return({}), get_result(sp) ); + } - terminate_scope_early(sp, fcn_scope()); + terminate_scope_early(sp, fcn_scope()); - end_block( ::MIR::Terminator::make_Return({}) ); + end_block( ::MIR::Terminator::make_Return({}) ); + } + } + else + { + terminate_scope(sp, ScopeHandle(*this, 1), /*emit_cleanup=*/false); + terminate_scope(sp, mv$(m_fcn_scope), /*emit_cleanup=*/false); } } |