summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge <tpg@ucc.asn.au>2017-11-26 18:28:08 +0800
committerJohn Hodge <tpg@ucc.asn.au>2017-11-26 18:28:08 +0800
commitad4d5ab92a8317428e066b70977333be106abaa0 (patch)
tree1d6f34f219d2f77fb5c85526f9bc6a23bb8e9604
parente335207c353efec94963e273d2fc3294afc860e0 (diff)
downloadmrust-ad4d5ab92a8317428e066b70977333be106abaa0.tar.gz
HIR/MIR - Error checking for assigning into ! (as opposed to from !)
-rw-r--r--src/hir_typeck/expr_check.cpp31
-rw-r--r--src/hir_typeck/expr_cs.cpp4
-rw-r--r--src/mir/check.cpp44
-rw-r--r--src/mir/from_hir.cpp7
-rw-r--r--src/mir/from_hir.hpp3
-rw-r--r--src/mir/mir_builder.cpp26
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);
}
}