diff options
author | John Hodge <tpg@mutabah.net> | 2016-10-01 10:36:43 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2016-10-01 10:36:43 +0800 |
commit | 7ab71bed81dbaa42c670e84eb74de63048db0ccf (patch) | |
tree | 3fd442faa613d4767054e3a5f20859e0d06415ed /src | |
parent | 8aa16a2533a6ad2417707f1c720e6b8b2ca6e660 (diff) | |
download | mrust-7ab71bed81dbaa42c670e84eb74de63048db0ccf.tar.gz |
HIR Typecheck Expr - Handle posibly-diverging loop blocks correctly
Diffstat (limited to 'src')
-rw-r--r-- | src/hir/expr.hpp | 3 | ||||
-rw-r--r-- | src/hir/from_ast_expr.cpp | 3 | ||||
-rw-r--r-- | src/hir_typeck/expr_cs.cpp | 35 | ||||
-rw-r--r-- | src/hir_typeck/helpers.cpp | 4 |
4 files changed, 36 insertions, 9 deletions
diff --git a/src/hir/expr.hpp b/src/hir/expr.hpp index d3bc8ad0..569f1b9d 100644 --- a/src/hir/expr.hpp +++ b/src/hir/expr.hpp @@ -107,7 +107,8 @@ struct ExprNode_Loop: ::HIR::ExprNodeP m_code; ExprNode_Loop(Span sp, ::std::string label, ::HIR::ExprNodeP code): - ExprNode(mv$(sp), ::HIR::TypeRef::new_unit()), + //ExprNode(mv$(sp), ::HIR::TypeRef::new_unit()), + ExprNode(mv$(sp), ::HIR::TypeRef()), m_label( mv$(label) ), m_code( mv$(code) ) {} diff --git a/src/hir/from_ast_expr.cpp b/src/hir/from_ast_expr.cpp index b3251e20..d0877c5f 100644 --- a/src/hir/from_ast_expr.cpp +++ b/src/hir/from_ast_expr.cpp @@ -295,7 +295,6 @@ struct LowerHIR_ExprNode_Visitor: v.m_label, LowerHIR_ExprNode_Inner(*v.m_code) ) ); - assert( m_rv->m_res_type.m_data.is_Tuple() ); break; case ::AST::ExprNode_Loop::WHILE: { ::std::vector< ::HIR::ExprNodeP> code; @@ -311,7 +310,6 @@ struct LowerHIR_ExprNode_Visitor: v.m_label, ::HIR::ExprNodeP(new ::HIR::ExprNode_Block( v.span(), false, mv$(code))) ) ); - assert( m_rv->m_res_type.m_data.is_Tuple() ); break; } case ::AST::ExprNode_Loop::WHILELET: { ::std::vector< ::HIR::ExprNode_Match::Arm> arms; @@ -336,7 +334,6 @@ struct LowerHIR_ExprNode_Visitor: mv$(arms) )) ) ); - assert( m_rv->m_res_type.m_data.is_Tuple() ); break; } case ::AST::ExprNode_Loop::FOR: // NOTE: This should already be desugared (as a pass before resolve) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index abe418a7..9d2af58e 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -461,6 +461,8 @@ namespace { ::std::vector<bool> inner_coerce_enabled_stack; + ::std::vector<const ::HIR::ExprNode_Loop*> loop_blocks; // Used for `break` type markings + // TEMP: List of in-scope traits for buildup ::HIR::t_trait_list m_traits; public: @@ -557,19 +559,44 @@ namespace { { auto _ = this->push_inner_coerce_scoped(false); TRACE_FUNCTION_F(&node << " loop { ... }"); + // Push this node to a stack so `break` statements can update the yeilded value + this->loop_blocks.push_back( &node ); - this->context.equate_types(node.span(), node.m_res_type, ::HIR::TypeRef::new_unit()); - // TODO: This is more correct, but could cause variables to be falsely marked as ! - //this->context.equate_types(node.span(), node.m_res_type, ::HIR::TypeRef::new_diverge()); + // TODO: This only yields unit if it terminates - otherwise it's ! + // - There's an RFC proposal (that's on track to be accepted) that allows `break value;` + // NOTE: This doesn't set the ivar to !, but marks it as a ! ivar (similar to the int/float markers) + this->context.equate_types(node.span(), node.m_res_type, ::HIR::TypeRef::new_diverge()); this->context.add_ivars(node.m_code->m_res_type); this->context.equate_types(node.span(), node.m_code->m_res_type, ::HIR::TypeRef::new_unit()); node.m_code->visit( *this ); + + this->loop_blocks.pop_back( ); } void visit(::HIR::ExprNode_LoopControl& node) override { TRACE_FUNCTION_F(&node << " " << (node.m_continue ? "continue" : "break") << " '" << node.m_label); - // Nothing + // Break types + if( !node.m_continue ) + { + if( this->loop_blocks.empty() ) { + ERROR(node.span(), E0000, "Break statement with no acive loop"); + } + if( node.m_label != "" ) + { + auto it = ::std::find_if(this->loop_blocks.rbegin(), this->loop_blocks.rend(), [&](const auto& np){ return np->m_label == node.m_label; }); + if( it == this->loop_blocks.rend() ) { + ERROR(node.span(), E0000, "Could not find loop '" << node.m_label << " for break"); + } + const auto& loop_node = **it; + this->context.equate_types(node.span(), loop_node.m_res_type, ::HIR::TypeRef::new_unit()); + } + else + { + const auto& loop_node = *this->loop_blocks.back(); + this->context.equate_types(node.span(), loop_node.m_res_type, ::HIR::TypeRef::new_unit()); + } + } } void visit(::HIR::ExprNode_Let& node) override diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index cc580a58..ade4cf6d 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -2292,6 +2292,8 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, } const auto& ty = *ty_p; DEBUG("[find_trait_impls_crate] - Compare " << ty << " and " << assoc_bound.second << ", matching generics"); + // `ty` = Monomorphised actual type (< `be.type` as `be.trait` >::`assoc_bound.first`) + // `assoc_bound.second` = Desired type (monomorphised too) auto cmp = assoc_bound.second .match_test_generics_fuzz(sp, ty, cb_infer, cb_match); switch(cmp) { @@ -2299,7 +2301,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, DEBUG("Equal"); continue; case ::HIR::Compare::Unequal: - DEBUG("Assoc failure - " << ty << " != " << assoc_bound.second); + DEBUG("Assoc " << assoc_bound.first << " failure - " << ty << " != " << assoc_bound.second); return false; case ::HIR::Compare::Fuzzy: // TODO: When a fuzzy match is encountered on a conditional bound, returning `false` can lead to an false negative (and a compile error) |