diff options
-rw-r--r-- | gcc/rust/backend/rust-compile-context.h | 12 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-expr.h | 46 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-expr.h | 28 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check.h | 23 | ||||
-rw-r--r-- | gcc/testsuite/rust.test/compilable/loop5.rs | 14 |
5 files changed, 119 insertions, 4 deletions
diff --git a/gcc/rust/backend/rust-compile-context.h b/gcc/rust/backend/rust-compile-context.h index 8a74a05..288b917 100644 --- a/gcc/rust/backend/rust-compile-context.h +++ b/gcc/rust/backend/rust-compile-context.h @@ -208,6 +208,17 @@ public: return false; } + void push_loop_context (Bvariable *var) { loop_value_stack.push_back (var); } + + Bvariable *peek_loop_context () { return loop_value_stack.back (); } + + Bvariable *pop_loop_context () + { + auto back = loop_value_stack.back (); + loop_value_stack.pop_back (); + return back; + } + private: ::Backend *backend; Resolver::Resolver *resolver; @@ -223,6 +234,7 @@ private: std::map<HirId, ::Blabel *> compiled_labels; std::vector< ::std::vector<Bstatement *> > statements; std::vector< ::Bblock *> scope_stack; + std::vector< ::Bvariable *> loop_value_stack; // To GCC middle-end std::vector< ::Btype *> type_decls; diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust-compile-expr.h index 189118b..7b25c5e 100644 --- a/gcc/rust/backend/rust-compile-expr.h +++ b/gcc/rust/backend/rust-compile-expr.h @@ -586,7 +586,31 @@ public: void visit (HIR::LoopExpr &expr) { + TyTy::TyBase *block_tyty = nullptr; + if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), + &block_tyty)) + { + rust_error_at (expr.get_locus (), "failed to lookup type of BlockExpr"); + return; + } + fncontext fnctx = ctx->peek_fn (); + Bvariable *tmp = NULL; + bool needs_temp = block_tyty->get_kind () != TyTy::TypeKind::UNIT; + if (needs_temp) + { + Bblock *enclosing_scope = ctx->peek_enclosing_scope (); + Btype *block_type = TyTyResolveCompile::compile (ctx, block_tyty); + + bool is_address_taken = false; + Bstatement *ret_var_stmt = nullptr; + tmp = ctx->get_backend ()->temporary_variable ( + fnctx.fndecl, enclosing_scope, block_type, NULL, is_address_taken, + expr.get_locus (), &ret_var_stmt); + ctx->add_statement (ret_var_stmt); + ctx->push_loop_context (tmp); + } + if (expr.has_loop_label ()) { HIR::LoopLabel &loop_label = expr.get_loop_label (); @@ -608,10 +632,32 @@ public: Bstatement *loop_stmt = ctx->get_backend ()->expression_statement (fnctx.fndecl, loop_expr); ctx->add_statement (loop_stmt); + + if (tmp != NULL) + { + ctx->pop_loop_context (); + translated + = ctx->get_backend ()->var_expression (tmp, expr.get_locus ()); + } } void visit (HIR::BreakExpr &expr) { + if (expr.has_break_expr ()) + { + fncontext fnctx = ctx->peek_fn (); + Bexpression *compiled_expr + = CompileExpr::Compile (expr.get_expr ().get (), ctx); + + Bvariable *loop_result_holder = ctx->peek_loop_context (); + Bexpression *result_reference = ctx->get_backend ()->var_expression ( + loop_result_holder, expr.get_expr ()->get_locus_slow ()); + + Bstatement *assignment = ctx->get_backend ()->assignment_statement ( + fnctx.fndecl, result_reference, compiled_expr, expr.get_locus ()); + ctx->add_statement (assignment); + } + if (expr.has_label ()) { NodeId resolved_node_id = UNKNOWN_NODEID; diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h index 6a45fef..87aeae6 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.h +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h @@ -757,7 +757,19 @@ public: void visit (HIR::LoopExpr &expr) { - infered = TypeCheckExpr::Resolve (expr.get_loop_block ().get (), true); + context->push_new_loop_context (expr.get_mappings ().get_hirid ()); + TypeCheckExpr::Resolve (expr.get_loop_block ().get (), true); + TyTy::TyBase *loop_context_type = context->pop_loop_context (); + + bool loop_context_type_infered + = (loop_context_type->get_kind () != TyTy::TypeKind::INFER) + || ((loop_context_type->get_kind () == TyTy::TypeKind::INFER) + && (((TyTy::InferType *) loop_context_type)->get_infer_kind () + != TyTy::InferType::GENERAL)); + + infered = loop_context_type_infered + ? loop_context_type + : new TyTy::UnitType (expr.get_mappings ().get_hirid ()); } void visit (HIR::BreakExpr &expr) @@ -768,9 +780,17 @@ public: return; } - infered = expr.has_break_expr () - ? TypeCheckExpr::Resolve (expr.get_expr ().get (), false) - : new TyTy::UnitType (expr.get_mappings ().get_hirid ()); + if (expr.has_break_expr ()) + { + TyTy::TyBase *break_expr_tyty + = TypeCheckExpr::Resolve (expr.get_expr ().get (), false); + + TyTy::TyBase *loop_context = context->peek_loop_context (); + TyTy::TyBase *combined = loop_context->combine (break_expr_tyty); + context->swap_head_loop_context (combined); + } + + infered = new TyTy::UnitType (expr.get_mappings ().get_hirid ()); } private: diff --git a/gcc/rust/typecheck/rust-hir-type-check.h b/gcc/rust/typecheck/rust-hir-type-check.h index d033878..531d241 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.h +++ b/gcc/rust/typecheck/rust-hir-type-check.h @@ -56,6 +56,28 @@ public: } } + void push_new_loop_context (HirId id) + { + TyTy::TyBase *infer_var + = new TyTy::InferType (id, TyTy::InferType::InferTypeKind::GENERAL); + loop_type_stack.push_back (infer_var); + } + + TyTy::TyBase *peek_loop_context () { return loop_type_stack.back (); } + + TyTy::TyBase *pop_loop_context () + { + auto back = peek_loop_context (); + loop_type_stack.pop_back (); + return back; + } + + void swap_head_loop_context (TyTy::TyBase *val) + { + loop_type_stack.pop_back (); + loop_type_stack.push_back (val); + } + private: TypeCheckContext (); @@ -63,6 +85,7 @@ private: std::map<HirId, TyTy::TyBase *> resolved; std::vector<std::unique_ptr<TyTy::TyBase> > builtins; std::vector<TyTy::TyBase *> return_type_stack; + std::vector<TyTy::TyBase *> loop_type_stack; }; class TypeResolution diff --git a/gcc/testsuite/rust.test/compilable/loop5.rs b/gcc/testsuite/rust.test/compilable/loop5.rs new file mode 100644 index 0000000..4004cd3 --- /dev/null +++ b/gcc/testsuite/rust.test/compilable/loop5.rs @@ -0,0 +1,14 @@ +fn main() { + let mut a = 1; + let mut b = 1; + + // first number in Fibonacci sequence over 10: + let _fib = loop { + if b > 10 { + break b; + } + let c = a + b; + a = b; + b = c; + }; +} |