namespace Rust {
namespace BIR {
+using LoopAndLabelCtx = BuilderContext::LoopAndLabelCtx;
+
+BuilderContext::LoopAndLabelCtx &
+ExprStmtBuilder::setup_loop (HIR::BaseLoopExpr &expr)
+{
+ NodeId label
+ = (expr.has_loop_label ())
+ ? expr.get_loop_label ().get_lifetime ().get_mappings ().get_nodeid ()
+ : UNKNOWN_NODEID;
+ PlaceId label_var = take_or_create_return_place (lookup_type (expr));
+
+ BasicBlockId continue_bb = new_bb ();
+ BasicBlockId break_bb = new_bb ();
+ ctx.loop_and_label_stack.push_back (
+ {true, label, label_var, break_bb, continue_bb});
+ return ctx.loop_and_label_stack.back ();
+}
+
+BuilderContext::LoopAndLabelCtx &
+ExprStmtBuilder::get_label_ctx (HIR::Lifetime &label)
+{
+ NodeId label_id = resolve_label (label);
+ auto lookup = std::find_if (ctx.loop_and_label_stack.rbegin (),
+ ctx.loop_and_label_stack.rend (),
+ [label_id] (LoopAndLabelCtx &info) {
+ return info.label == label_id;
+ });
+ rust_assert (lookup != ctx.loop_and_label_stack.rend ());
+ return *lookup;
+}
+
+LoopAndLabelCtx &
+ExprStmtBuilder::get_unnamed_loop_ctx ()
+{
+ auto lookup
+ = std::find_if (ctx.loop_and_label_stack.rbegin (),
+ ctx.loop_and_label_stack.rend (),
+ [] (LoopAndLabelCtx &info) { return info.is_loop; });
+ rust_assert (lookup != ctx.loop_and_label_stack.rend ());
+ return *lookup;
+}
+
void
ExprStmtBuilder::visit (HIR::ClosureExpr &expr)
{
{
captures.push_back (ctx.place_db.lookup_variable (capture));
}
+ make_args (captures);
- // Not a coercion site.
+ // Note: Not a coercion site for captures.
return_expr (new InitializerExpr (std::move (captures)), lookup_type (expr));
}
auto struct_ty
= lookup_type (fields)->as<TyTy::ADTType> ()->get_variants ().at (0);
auto init_values = StructBuilder (ctx, struct_ty).build (fields);
+ make_args (init_values);
return_expr (new InitializerExpr (std::move (init_values)),
lookup_type (fields));
}
void
ExprStmtBuilder::visit (HIR::LiteralExpr &expr)
{
- // Different literal values of the same type are not distinguished.
+ // Different literal values of the same type are not distinguished in BIR.
return_place (ctx.place_db.get_constant (lookup_type (expr)));
}
ExprStmtBuilder::visit (HIR::DereferenceExpr &expr)
{
auto operand = visit_expr (*expr.get_expr ());
- return_place (operand);
+ return_place (ctx.place_db.lookup_or_add_path (Place::DEREF,
+ lookup_type (expr), operand));
}
void
ExprStmtBuilder::visit (HIR::ErrorPropagationExpr &expr)
{
+ // TODO: desugar in AST->HIR
rust_sorry_at (expr.get_locus (), "error propagation is not supported");
}
ExprStmtBuilder::visit (HIR::NegationExpr &expr)
{
PlaceId operand = visit_expr (*expr.get_expr ());
- return_expr (new Operator<1> ({operand}), lookup_type (expr));
+ return_expr (new Operator<1> ({make_arg (operand)}), lookup_type (expr));
}
void
{
PlaceId lhs = visit_expr (*expr.get_lhs ());
PlaceId rhs = visit_expr (*expr.get_rhs ());
- return_expr (new Operator<2> ({lhs, rhs}), lookup_type (expr));
+ return_expr (new Operator<2> ({make_arg (lhs), make_arg (rhs)}),
+ lookup_type (expr));
}
void
{
PlaceId lhs = visit_expr (*expr.get_lhs ());
PlaceId rhs = visit_expr (*expr.get_rhs ());
- return_expr (new Operator<2> ({lhs, rhs}), lookup_type (expr));
+ return_expr (new Operator<2> ({make_arg (lhs), make_arg (rhs)}),
+ lookup_type (expr));
}
void
ExprStmtBuilder::visit (HIR::LazyBooleanExpr &expr)
{
- return_place (LazyBooleanExprBuilder (ctx).build (expr));
+ return_place (LazyBooleanExprBuilder (ctx, take_or_create_return_place (
+ lookup_type (expr)))
+ .build (expr));
}
void
ExprStmtBuilder::visit (HIR::TypeCastExpr &expr)
{
- return_place (visit_expr (*expr.get_expr ()));
+ auto operand = visit_expr (*expr.get_expr ());
+ return_expr (new Operator<1> ({operand}), lookup_type (expr));
}
void
auto lhs = visit_expr (*expr.get_lhs ());
auto rhs = visit_expr (*expr.get_rhs ());
push_assignment (lhs, new Operator<2> ({lhs, rhs}));
- // TODO: (philip) nicer unit?
- return_place (ctx.place_db.get_constant (lookup_type (expr)));
}
void
ExprStmtBuilder::visit (HIR::GroupedExpr &expr)
{
- // Uses accept_vis directly to avoid creating n new temporary.
- expr.get_expr_in_parens ()->accept_vis (*this);
+ return_place (visit_expr (*expr.get_expr_in_parens ()));
}
void
ExprStmtBuilder::visit (HIR::ArrayExpr &expr)
{
- switch (expr.get_internal_elements ()->get_array_expr_type ())
+ auto &elems = expr.get_internal_elements ();
+ switch (elems->get_array_expr_type ())
{
case HIR::ArrayElems::VALUES: {
- auto init_values = visit_list ((static_cast<HIR::ArrayElemsValues *> (
- expr.get_internal_elements ().get ()))
- ->get_values ());
+ auto &elem_vals = (static_cast<HIR::ArrayElemsValues &> (*elems));
+ auto init_values = visit_list (elem_vals.get_values ());
+ make_args (init_values);
return_expr (new InitializerExpr (std::move (init_values)),
lookup_type (expr));
break;
}
case HIR::ArrayElems::COPIED: {
- auto init = visit_expr (*(static_cast<HIR::ArrayElemsCopied *> (
- expr.get_internal_elements ().get ()))
- ->get_elem_to_copy ());
+ auto &elem_copied = (static_cast<HIR::ArrayElemsCopied &> (*elems));
+ auto init = visit_expr (*elem_copied.get_elem_to_copy ());
return_expr (new InitializerExpr ({init}), lookup_type (expr));
break;
}
{
auto lhs = visit_expr (*expr.get_array_expr ());
auto rhs = visit_expr (*expr.get_index_expr ());
- // The Index is not tracked in BIR.
+ // The index is not tracked in BIR.
(void) rhs;
return_place (
ctx.place_db.lookup_or_add_path (Place::INDEX, lookup_type (expr), lhs));
ExprStmtBuilder::visit (HIR::TupleExpr &expr)
{
std::vector<PlaceId> init_values = visit_list (expr.get_tuple_elems ());
- if (std::any_of (init_values.begin (), init_values.end (),
- [this] (PlaceId id) {
- return ctx.place_db[id].lifetime.has_lifetime ();
- }))
- {
- ctx.place_db[expr_return_place].lifetime
- = {ctx.lifetime_interner.get_anonymous ()};
- }
return_expr (new InitializerExpr (std::move (init_values)),
lookup_type (expr));
}
PlaceId fn = visit_expr (*expr.get_fnexpr ());
std::vector<PlaceId> arguments = visit_list (expr.get_arguments ());
- TyTy::BaseType *call_type = ctx.place_db[fn].tyty;
+ auto *call_type = ctx.place_db[fn].tyty;
if (auto fn_type = call_type->try_as<TyTy::FnType> ())
{
for (size_t i = 0; i < fn_type->get_params ().size (); ++i)
true);
}
+void
+ExprStmtBuilder::visit (HIR::MethodCallExpr &expr)
+{}
+
void
ExprStmtBuilder::visit (HIR::FieldAccessExpr &expr)
{
auto adt = type->as<TyTy::ADTType> ();
rust_assert (!adt->is_enum ());
rust_assert (adt->number_of_variants () == 1);
- TyTy::VariantDef *variant = adt->get_variants ().at (0);
+ auto struct_ty = adt->get_variants ().at (0);
TyTy::StructFieldType *field_ty = nullptr;
size_t field_index = 0;
- bool ok = variant->lookup_field (expr.get_field_name ().as_string (),
- &field_ty, &field_index);
+ bool ok = struct_ty->lookup_field (expr.get_field_name ().as_string (),
+ &field_ty, &field_index);
rust_assert (ok);
return_place (ctx.place_db.lookup_or_add_path (Place::FIELD,
void
ExprStmtBuilder::visit (HIR::BlockExpr &block)
{
- BasicBlockId end_bb;
-
if (block.has_label ())
{
- end_bb = new_bb ();
NodeId label
= block.get_label ().get_lifetime ().get_mappings ().get_nodeid ();
- PlaceId label_var = ctx.place_db.add_temporary (lookup_type (block));
- ctx.loop_and_label_stack.push_back ({false, label, label_var, end_bb, 0});
+ PlaceId label_var = take_or_create_return_place (lookup_type (block));
+ ctx.loop_and_label_stack.push_back (
+ {false, label, label_var, new_bb (), INVALID_BB});
}
+ // Eliminates dead code after break, continue, return.
bool unreachable = false;
for (auto &stmt : block.get_statements ())
{
- if (unreachable)
- break;
stmt->accept_vis (*this);
if (ctx.get_current_bb ().is_terminated ())
- unreachable = true;
+ {
+ unreachable = true;
+ break;
+ }
}
if (block.has_label ())
{
- auto label_info = ctx.loop_and_label_stack.back ();
+ auto block_ctx = ctx.loop_and_label_stack.back ();
if (block.has_expr () && !unreachable)
{
- push_assignment (label_info.label_var,
+ push_assignment (block_ctx.label_var,
visit_expr (*block.get_final_expr ()));
}
if (!ctx.get_current_bb ().is_terminated ())
{
- add_jump_to (end_bb);
+ push_goto (block_ctx.break_bb);
}
- ctx.current_bb = end_bb;
+ ctx.current_bb = block_ctx.break_bb;
ctx.loop_and_label_stack.pop_back ();
- return_place (label_info.label_var);
+ return_place (block_ctx.label_var);
}
else if (block.has_expr () && !unreachable)
{
- return_place (visit_expr (*block.get_final_expr ()));
+ return_place (visit_expr (*block.get_final_expr (),
+ take_or_create_return_place (
+ lookup_type (*block.get_final_expr ()))));
}
}
void
ExprStmtBuilder::visit (HIR::ContinueExpr &cont)
{
- BuilderContext::LoopAndLabelInfo info;
- if (cont.has_label ())
- {
- NodeId label = resolve_label (cont.get_label ());
- auto lookup
- = std::find_if (ctx.loop_and_label_stack.rbegin (),
- ctx.loop_and_label_stack.rend (),
- [label] (const BuilderContext::LoopAndLabelInfo &info) {
- return info.label == label;
- });
- rust_assert (lookup != ctx.loop_and_label_stack.rend ());
- info = *lookup;
- }
- else
- {
- auto lookup
- = std::find_if (ctx.loop_and_label_stack.rbegin (),
- ctx.loop_and_label_stack.rend (),
- [] (const BuilderContext::LoopAndLabelInfo &info) {
- return info.is_loop;
- });
- rust_assert (lookup != ctx.loop_and_label_stack.rend ());
- info = *lookup;
- }
+ LoopAndLabelCtx info = cont.has_label () ? get_label_ctx (cont.get_label ())
+ : get_unnamed_loop_ctx ();
push_goto (info.continue_bb);
- // No code allowed after continue. No BB starts - would be empty.
+ // No code allowed after continue. Handled in BlockExpr.
}
void
ExprStmtBuilder::visit (HIR::BreakExpr &brk)
{
- BuilderContext::LoopAndLabelInfo info;
- if (brk.has_label ())
- {
- NodeId label = resolve_label (brk.get_label ());
- auto lookup
- = std::find_if (ctx.loop_and_label_stack.rbegin (),
- ctx.loop_and_label_stack.rend (),
- [label] (const BuilderContext::LoopAndLabelInfo &info) {
- return info.label == label;
- });
- rust_assert (lookup != ctx.loop_and_label_stack.rend ());
- info = *lookup;
- }
- else
- {
- auto lookup
- = std::find_if (ctx.loop_and_label_stack.rbegin (),
- ctx.loop_and_label_stack.rend (),
- [] (const BuilderContext::LoopAndLabelInfo &info) {
- return info.is_loop;
- });
- rust_assert (lookup != ctx.loop_and_label_stack.rend ());
- info = *lookup;
- }
+ LoopAndLabelCtx info = brk.has_label () ? get_label_ctx (brk.get_label ())
+ : get_unnamed_loop_ctx ();
if (brk.has_break_expr ())
- {
- push_assignment (info.label_var, visit_expr (*brk.get_expr ()));
- }
+ push_assignment (info.label_var, visit_expr (*brk.get_expr ()));
+
push_goto (info.break_bb);
- // No code allowed after break. No BB starts - would be empty.
+ // No code allowed after continue. Handled in BlockExpr.
}
void
rust_sorry_at (expr.get_locus (), "unsafe blocks are not supported");
}
-BuilderContext::LoopAndLabelInfo &
-ExprStmtBuilder::setup_loop (HIR::BaseLoopExpr &expr)
-{
- NodeId label
- = (expr.has_loop_label ())
- ? expr.get_loop_label ().get_lifetime ().get_mappings ().get_nodeid ()
- : UNKNOWN_NODEID;
- PlaceId label_var = ctx.place_db.add_temporary (lookup_type (expr));
-
- BasicBlockId continue_bb = new_bb ();
- BasicBlockId break_bb = new_bb ();
- ctx.loop_and_label_stack.push_back (
- {true, label, label_var, break_bb, continue_bb});
- return ctx.loop_and_label_stack.back ();
-}
-
void
ExprStmtBuilder::visit (HIR::LoopExpr &expr)
{
void
ExprStmtBuilder::visit (HIR::IfExprConseqElse &expr)
{
- PlaceId result = ctx.place_db.add_temporary (lookup_type (expr));
+ push_switch (make_arg (visit_expr (*expr.get_if_condition ())));
+ BasicBlockId if_end_bb = ctx.current_bb;
- push_switch (visit_expr (*expr.get_if_condition ()));
- BasicBlockId if_block = ctx.current_bb;
+ PlaceId result = take_or_create_return_place (lookup_type (expr));
ctx.current_bb = new_bb ();
- auto then_res = visit_expr (*expr.get_if_block ());
- push_assignment (result, then_res);
+ BasicBlockId then_start_bb = ctx.current_bb;
+ (void) visit_expr (*expr.get_if_block (), result);
if (!ctx.get_current_bb ().is_terminated ())
push_goto (INVALID_BB); // Resolved later.
- BasicBlockId then_block = ctx.current_bb;
+ BasicBlockId then_end_bb = ctx.current_bb;
ctx.current_bb = new_bb ();
- auto else_res = visit_expr (*expr.get_else_block ());
- push_assignment (result, else_res);
+ BasicBlockId else_start_bb = ctx.current_bb;
+ (void) visit_expr (*expr.get_else_block (), result);
if (!ctx.get_current_bb ().is_terminated ())
push_goto (INVALID_BB); // Resolved later.
- BasicBlockId else_block = ctx.current_bb;
+ BasicBlockId else_end_bb = ctx.current_bb;
ctx.current_bb = new_bb ();
- BasicBlockId final_block = ctx.current_bb;
+ BasicBlockId final_start_bb = ctx.current_bb;
return_place (result);
// Jumps are added at the end to match rustc MIR order for easier comparison.
- add_jump (if_block, then_block);
- add_jump (if_block, else_block);
+ add_jump (if_end_bb, then_start_bb);
+ add_jump (if_end_bb, else_start_bb);
- auto &then_bb = ctx.basic_blocks[then_block];
+ auto &then_bb = ctx.basic_blocks[then_end_bb];
if (then_bb.is_goto_terminated () && then_bb.successors.empty ())
- add_jump (then_block, final_block);
+ add_jump (then_end_bb, final_start_bb);
- auto &else_bb = ctx.basic_blocks[else_block];
+ auto &else_bb = ctx.basic_blocks[else_end_bb];
if (else_bb.is_goto_terminated () && else_bb.successors.empty ())
- add_jump (else_block, final_block);
+ add_jump (else_end_bb, final_start_bb);
}
void
ExprStmtBuilder::visit (HIR::IfLetExpr &expr)
void
ExprStmtBuilder::visit (HIR::MatchExpr &expr)
{
+ rust_sorry_at (expr.get_locus (), "match expressions are not supported");
// // TODO
// expr.get_scrutinee_expr ()->accept_vis (*this);
// PlaceId scrutinee = translated;
void
ExprStmtBuilder::visit (HIR::QualifiedPathInExpression &expr)
{
- PlaceId result;
// Note: Type is only stored for the expr, not the segment.
- bool ok = resolve_variable (expr.get_final_segment (), result);
- rust_assert (ok);
+ PlaceId result
+ = resolve_variable_or_fn (expr.get_final_segment (), lookup_type (expr));
return_place (result);
}
void
ExprStmtBuilder::visit (HIR::PathInExpression &expr)
{
- PlaceId result;
// Note: Type is only stored for the expr, not the segment.
- bool ok = resolve_variable (expr.get_final_segment (), result);
- rust_assert (ok);
+ PlaceId result
+ = resolve_variable_or_fn (expr.get_final_segment (), lookup_type (expr));
return_place (result);
}
void
ExprStmtBuilder::visit (HIR::LetStmt &stmt)
{
- if (stmt.has_init_expr ())
- {
- auto init = visit_expr (*stmt.get_init_expr ());
- PatternBindingBuilder (ctx, init, stmt.get_type ().get ())
- .go (*stmt.get_pattern ());
- }
- else if (stmt.get_pattern ()->get_pattern_type () == HIR::Pattern::IDENTIFIER)
+ if (stmt.get_pattern ()->get_pattern_type () == HIR::Pattern::IDENTIFIER)
{
+ // Only if a pattern is just an identifier, no destructuring is needed.
+ // Hoverer PatternBindingBuilder cannot change existing temporary
+ // (init expr is evaluated before pattern binding) into a
+ // variable, so it would emit extra assignment.
auto var = declare_variable (stmt.get_pattern ()->get_mappings ());
auto &var_place = ctx.place_db[var];
if (var_place.tyty->get_kind () == TyTy::REF)
{
- auto p_type = tl::optional<HIR::ReferenceType *> (
- static_cast<HIR::ReferenceType *> (stmt.get_type ().get ()));
var_place.lifetime = ctx.lookup_lifetime (
- p_type.map (&HIR::ReferenceType::get_lifetime));
+ optional_from_ptr (
+ static_cast<HIR::ReferenceType *> (stmt.get_type ().get ()))
+ .map (&HIR::ReferenceType::get_lifetime));
}
- return;
+ if (stmt.has_init_expr ())
+ (void) visit_expr (*stmt.get_init_expr (), var);
+ }
+ else if (stmt.has_init_expr ())
+ {
+ auto init = visit_expr (*stmt.get_init_expr ());
+ PatternBindingBuilder (ctx, init, stmt.get_type ().get ())
+ .go (*stmt.get_pattern ());
}
else
{
namespace Rust {
namespace BIR {
+/**
+ * Compiles expressions into a BIR place.
+ * See AbstractExprBuilder for API usage docs (mainly `return_place` and
+ * `return_expr`).
+ */
class ExprStmtBuilder : public AbstractExprBuilder, public HIR::HIRStmtVisitor
{
- PlaceId expr_return_place = INVALID_PLACE;
-
public:
explicit ExprStmtBuilder (BuilderContext &ctx) : AbstractExprBuilder (ctx) {}
- PlaceId build (HIR::Expr &expr) { return visit_expr (expr); }
+ /** Entry point. */
+ PlaceId build (HIR::Expr &expr, PlaceId place = INVALID_PLACE)
+ {
+ return visit_expr (expr, place);
+ }
private:
template <typename T>
return result;
}
- BuilderContext::LoopAndLabelInfo &setup_loop (HIR::BaseLoopExpr &expr);
+ /** Common infrastructure for loops. */
+ BuilderContext::LoopAndLabelCtx &setup_loop (HIR::BaseLoopExpr &expr);
+
+ BuilderContext::LoopAndLabelCtx &get_label_ctx (HIR::Lifetime &label);
+ BuilderContext::LoopAndLabelCtx &get_unnamed_loop_ctx ();
protected: // Expr
- // TODO: test when compiles
void visit (HIR::ClosureExpr &expr) override;
void visit (HIR::StructExprStructFields &fields) override;
void visit (HIR::StructExprStruct &expr) override;
void visit (HIR::LiteralExpr &expr) override;
void visit (HIR::BorrowExpr &expr) override;
void visit (HIR::DereferenceExpr &expr) override;
- // TODO: desugar in AST->HIR
void visit (HIR::ErrorPropagationExpr &expr) override;
void visit (HIR::NegationExpr &expr) override;
void visit (HIR::ArithmeticOrLogicalExpr &expr) override;
void visit (HIR::TupleExpr &expr) override;
void visit (HIR::TupleIndexExpr &expr) override;
void visit (HIR::CallExpr &expr) override;
- void visit (HIR::MethodCallExpr &expr) override {}
+ void visit (HIR::MethodCallExpr &expr) override;
void visit (HIR::FieldAccessExpr &expr) override;
void visit (HIR::BlockExpr &block) override;
void visit (HIR::ContinueExpr &cont) override;
void visit (HIR::AwaitExpr &expr) override;
void visit (HIR::AsyncBlockExpr &expr) override;
- // Nodes not containing executable code. Nothing to do.
+protected: // Nodes not containing executable code. Nothing to do.
void visit (HIR::QualifiedPathInExpression &expr) override;
void visit (HIR::PathInExpression &expr) override;
void visit (HIR::ExprStmt &stmt) override;
-protected: // Unused
+protected: // Ignored.
// Only executable code of a single function/method is translated.
- // All other items are ignored.
void visit (HIR::EnumItemTuple &tuple) override {}
void visit (HIR::EnumItemStruct &a_struct) override {}
void visit (HIR::EnumItem &item) override {}
namespace BIR {
-class LifetimeResolver
+/** Holds the context of BIR building so that it can be shared/passed between
+ * different builders. */
+struct BuilderContext
{
- using Index = uint32_t;
- using Value = std::string;
+ class LifetimeResolver
+ {
+ using Index = uint32_t;
+ using Value = std::string;
- Index next_index = FIRST_NORMAL_LIFETIME_ID;
- std::unordered_map<Value, Index> value_to_index;
+ Index next_index = FIRST_NORMAL_LIFETIME_ID;
+ std::unordered_map<Value, Index> value_to_index;
-public:
- Index intern (const Value &value)
- {
- auto found = value_to_index.find (value);
- if (found != value_to_index.end ())
- {
- return found->second;
- }
- value_to_index.emplace (value, next_index);
- return next_index++;
- }
- Index get_anonymous () { return next_index++; }
-};
+ public:
+ Index resolve (const Value &value)
+ {
+ auto found = value_to_index.find (value);
+ if (found != value_to_index.end ())
+ {
+ return found->second;
+ }
+ value_to_index.emplace (value, next_index);
+ return next_index++;
+ }
-struct BuilderContext
-{
- struct LoopAndLabelInfo
+ /** Returns a new anonymous lifetime. */
+ Index get_anonymous () { return next_index++; }
+ };
+
+ struct LoopAndLabelCtx
{
bool is_loop; // Loop or labelled block
NodeId label; // UNKNOWN_NODEID if no label (loop)
BasicBlockId break_bb;
BasicBlockId continue_bb; // Only valid for loops
- LoopAndLabelInfo (bool is_loop = false, NodeId label = UNKNOWN_NODEID,
- PlaceId label_var = INVALID_PLACE,
- BasicBlockId break_bb = INVALID_BB,
- BasicBlockId continue_bb = INVALID_BB)
+ LoopAndLabelCtx (bool is_loop = false, NodeId label = UNKNOWN_NODEID,
+ PlaceId label_var = INVALID_PLACE,
+ BasicBlockId break_bb = INVALID_BB,
+ BasicBlockId continue_bb = INVALID_BB)
: is_loop (is_loop), label (label), label_var (label_var),
break_bb (break_bb), continue_bb (continue_bb)
{}
};
- // Context
+ // External context.
Resolver::TypeCheckContext &tyctx;
Resolver::Resolver &resolver;
+ // BIR output
std::vector<BasicBlock> basic_blocks;
size_t current_bb = 0;
*/
PlaceDB place_db;
LifetimeResolver lifetime_interner;
+ // Used for cleaner dump.
std::vector<PlaceId> arguments;
/**
* Since labels can be used to return values, we need to reserve a place for
*/
std::unordered_map<NodeId, PlaceId> label_place_map;
- std::vector<LoopAndLabelInfo> loop_and_label_stack;
+ /** Context for current situation (loop, label, etc.) */
+ std::vector<LoopAndLabelCtx> loop_and_label_stack;
public:
BuilderContext ()
switch (lifetime->get_lifetime_type ())
{
case AST::Lifetime::NAMED: {
- return {lifetime_interner.intern (lifetime->get_name ())};
+ return {lifetime_interner.resolve (lifetime->get_name ())};
}
case AST::Lifetime::STATIC: {
return STATIC_LIFETIME;
rust_unreachable ();
};
- const LoopAndLabelInfo &lookup_label (NodeId label)
+ const LoopAndLabelCtx &lookup_label (NodeId label)
{
- auto label_match = [label] (const LoopAndLabelInfo &info) {
+ auto label_match = [label] (const LoopAndLabelCtx &info) {
return info.label != UNKNOWN_NODEID && info.label == label;
};
}
};
-// Common infrastructure for building BIR from HIR.
+/** Common infrastructure for building BIR from HIR. */
class AbstractBuilder
{
protected:
BuilderContext &ctx;
- // This emulates the return value of the visitor, to be able to use the
- // current visitor infrastructure, where the return value is forced to be
- // void.
+ /**
+ * This emulates the return value of the visitor, to be able to use the
+ * current visitor infrastructure, where the return value is forced to be
+ * void.
+ */
PlaceId translated = INVALID_PLACE;
protected:
explicit AbstractBuilder (BuilderContext &ctx) : ctx (ctx) {}
- WARN_UNUSED_RESULT static NodeId get_nodeid (HIR::Expr &expr)
- {
- return expr.get_mappings ().get_nodeid ();
- }
-
- WARN_UNUSED_RESULT static NodeId get_nodeid (HIR::Pattern &pattern)
- {
- return pattern.get_mappings ().get_nodeid ();
- }
-
- template <typename T>
- WARN_UNUSED_RESULT TyTy::BaseType *lookup_type (T &pattern) const
- {
- return lookup_type (pattern.get_mappings ().get_hirid ());
- }
-
- WARN_UNUSED_RESULT TyTy::BaseType *lookup_type (HirId hirid) const
- {
- TyTy::BaseType *type = nullptr;
- bool ok = ctx.tyctx.lookup_type (hirid, &type);
- rust_assert (ok);
- rust_assert (type != nullptr);
- return type;
- }
-
PlaceId declare_variable (const Analysis::NodeMapping &node)
{
- const NodeId nodeid = node.get_nodeid ();
- const HirId hirid = node.get_hirid ();
-
- // In debug mode check that the variable is not already declared.
- rust_assert (ctx.place_db.lookup_variable (nodeid) == INVALID_PLACE);
-
- return ctx.place_db.add_variable (nodeid, lookup_type (hirid));
+ return declare_variable (node, lookup_type (node.get_hirid ()));
}
PlaceId declare_variable (const Analysis::NodeMapping &node,
- TyTy::BaseType *type)
+ TyTy::BaseType *ty)
{
const NodeId nodeid = node.get_nodeid ();
- // In debug mode check that the variable is not already declared.
+ // In debug mode, check that the variable is not already declared.
rust_assert (ctx.place_db.lookup_variable (nodeid) == INVALID_PLACE);
- return ctx.place_db.add_variable (nodeid, type);
+ return ctx.place_db.add_variable (nodeid, ty);
}
+protected: // Helpers to add BIR nodes
void push_assignment (PlaceId lhs, AbstractExpr *rhs)
{
ctx.get_current_bb ().statements.emplace_back (lhs, rhs);
void push_switch (PlaceId switch_val,
std::initializer_list<BasicBlockId> destinations = {})
{
- ctx.get_current_bb ().statements.emplace_back (Node::Kind::SWITCH,
- switch_val);
+ auto copy = make_arg (switch_val);
+ ctx.get_current_bb ().statements.emplace_back (Node::Kind::SWITCH, copy);
ctx.get_current_bb ().successors.insert (
ctx.get_current_bb ().successors.end (), destinations);
}
ctx.get_current_bb ().successors.push_back (bb);
}
- void push_storage_dead (PlaceId place)
+ PlaceId declare_rvalue (PlaceId place)
+ {
+ ctx.place_db[place].is_rvalue = true;
+ return place;
+ }
+
+ void declare_rvalues (std::vector<PlaceId> &places)
+ {
+ for (auto &place : places)
+ declare_rvalue (place);
+ }
+
+ PlaceId make_arg (PlaceId arg)
{
- ctx.get_current_bb ().statements.emplace_back (Node::Kind::STORAGE_DEAD,
- place);
+ auto copy = ctx.place_db.into_rvalue (arg);
+ if (copy != arg)
+ push_assignment (copy, arg);
+ return copy;
}
- void push_storage_live (PlaceId place)
+ void make_args (std::vector<PlaceId> &args)
{
- ctx.get_current_bb ().statements.emplace_back (Node::Kind::STORAGE_LIVE,
- place);
+ std::transform (args.begin (), args.end (), args.begin (),
+ [this] (PlaceId arg) { return make_arg (arg); });
}
+protected: // CFG helpers
BasicBlockId new_bb ()
{
ctx.basic_blocks.emplace_back ();
return ctx.basic_blocks.size () - 1;
}
- BasicBlockId start_new_subsequent_bb ()
+ BasicBlockId start_new_consecutive_bb ()
{
BasicBlockId bb = new_bb ();
ctx.get_current_bb ().successors.emplace_back (bb);
void add_jump_to (BasicBlockId bb) { add_jump (ctx.current_bb, bb); }
-protected:
+protected: // HIR resolution helpers
+ template <typename T>
+ [[nodiscard]] TyTy::BaseType *lookup_type (T &hir_node) const
+ {
+ return lookup_type (hir_node.get_mappings ().get_hirid ());
+ }
+
+ [[nodiscard]] TyTy::BaseType *lookup_type (HirId hirid) const
+ {
+ TyTy::BaseType *type = nullptr;
+ bool ok = ctx.tyctx.lookup_type (hirid, &type);
+ rust_assert (ok);
+ rust_assert (type != nullptr);
+ return type;
+ }
+
template <typename T> NodeId resolve_label (T &expr)
{
NodeId resolved_label;
return resolved_label;
}
- template <typename T>
- bool resolve_variable (T &variable, PlaceId &resolved_variable)
+ template <typename T> PlaceId resolve_variable (T &variable)
{
NodeId variable_id;
- if (!ctx.resolver.lookup_resolved_name (
- variable.get_mappings ().get_nodeid (), &variable_id))
- {
- // TODO: should this be assert? (should be caught by typecheck)
- rust_error_at (variable.get_locus (), "unresolved variable");
- return false;
- }
- resolved_variable = ctx.place_db.lookup_variable (variable_id);
- return true;
+ bool ok = ctx.resolver.lookup_resolved_name (
+ variable.get_mappings ().get_nodeid (), &variable_id);
+ rust_assert (ok);
+ return ctx.place_db.lookup_variable (variable_id);
}
- bool find_block_ctx (NodeId label, BuilderContext::LoopAndLabelInfo &block)
+ template <typename T>
+ PlaceId resolve_variable_or_fn (T &variable, TyTy::BaseType *ty)
{
- if (ctx.loop_and_label_stack.empty ())
- return false;
- if (label == UNKNOWN_NODEID)
- {
- block = ctx.loop_and_label_stack.back ();
- return true;
- }
- auto found
- = std::find_if (ctx.loop_and_label_stack.rbegin (),
- ctx.loop_and_label_stack.rend (),
- [&label] (const BuilderContext::LoopAndLabelInfo &block) {
- return block.label == label;
- });
- if (found == ctx.loop_and_label_stack.rend ())
- return false;
- block = *found;
- return true;
+ // Unlike variables,
+ // functions do not have to be declared in PlaceDB before use.
+ NodeId variable_id;
+ bool ok = ctx.resolver.lookup_resolved_name (
+ variable.get_mappings ().get_nodeid (), &variable_id);
+ rust_assert (ok);
+ return ctx.place_db.lookup_or_add_variable (variable_id,
+ (ty) ? ty
+ : lookup_type (variable));
}
+protected: // Implicit conversions.
/**
* Performs implicit coercions on the `translated` place defined for a
* coercion site.
return ty;
}
- /** For operator */
void autoref ()
{
if (ctx.place_db[translated].tyty->get_kind () != TyTy::REF)
public HIR::HIRExpressionVisitor
{
protected:
- // Exactly one of this and `translated` is used by each visitor.
- AbstractExpr *expr_return_expr = nullptr;
+ /**
+ * Optional place for the result of the evaluated expression.
+ * Valid if value is not `INVALID_PLACE`.
+ * Used when return place must be created by caller (return for if-else).
+ */
+ PlaceId expr_return_place = INVALID_PLACE;
protected:
- explicit AbstractExprBuilder (BuilderContext &ctx) : AbstractBuilder (ctx) {}
+ explicit AbstractExprBuilder (BuilderContext &ctx,
+ PlaceId expr_return_place = INVALID_PLACE)
+ : AbstractBuilder (ctx), expr_return_place (expr_return_place)
+ {}
- PlaceId visit_expr (HIR::Expr &expr)
+ /**
+ * Wrapper that provides return value based API inside a visitor which has to
+ * use global state to pass the data around.
+ * @param dst_place Place to assign the produced value to, optionally
+ * allocated by the caller.
+ * */
+ PlaceId visit_expr (HIR::Expr &expr, PlaceId dst_place = INVALID_PLACE)
{
- // Reset return places.
+ // Save to support proper recursion.
+ auto saved = expr_return_place;
+ expr_return_place = dst_place;
translated = INVALID_PLACE;
- expr_return_expr = nullptr;
expr.accept_vis (*this);
- if (translated != INVALID_PLACE)
+ expr_return_place = saved;
+ auto result = translated;
+ translated = INVALID_PLACE;
+ return result;
+ }
+
+ /**
+ * Create a return value of a subexpression, which produces an expression.
+ * Use `return_place` for subexpression that only produce a place (look it up)
+ * to avoid needless assignments.
+ *
+ * @param can_panic mark that expression can panic to insert jump to cleanup.
+ */
+ void return_expr (AbstractExpr *expr, TyTy::BaseType *ty,
+ bool can_panic = false)
+ {
+ if (expr_return_place != INVALID_PLACE)
{
- auto result = translated;
- translated = INVALID_PLACE;
- return result;
+ push_assignment (expr_return_place, expr);
}
- else if (expr_return_expr != nullptr)
+ else
{
- // Only allocate temporary, if needed.
- push_tmp_assignment (expr_return_expr, lookup_type (expr));
- expr_return_expr = nullptr;
- return translated;
+ push_tmp_assignment (expr, ty);
}
- else
+
+ if (can_panic)
{
- return ctx.place_db.get_constant (lookup_type (expr));
+ start_new_consecutive_bb ();
}
}
- void return_expr (AbstractExpr *expr, TyTy::BaseType *ty,
- bool can_panic = false)
+ /** Mark place to be a result of processed subexpression. */
+ void return_place (PlaceId place)
{
- rust_assert (expr_return_expr == nullptr);
- if (can_panic)
+ if (expr_return_place != INVALID_PLACE)
{
- push_tmp_assignment (expr, ty);
- // TODO, cleanup?
- start_new_subsequent_bb ();
+ // Return place is already allocated, no need to defer assignment.
+ push_assignment (expr_return_place, place);
}
else
{
- translated = INVALID_PLACE;
- expr_return_expr = expr;
+ translated = place;
}
}
- void return_place (PlaceId place)
+ /** Explicitly return a unit value. Expression produces no value. */
+ void return_unit (HIR::Expr &expr)
{
- expr_return_expr = nullptr;
- translated = place;
+ translated = ctx.place_db.get_constant (lookup_type (expr));
}
- void return_unit (HIR::Expr &expr)
+ PlaceId take_or_create_return_place (TyTy::BaseType *type)
{
- expr_return_expr = nullptr;
- translated = ctx.place_db.get_constant (lookup_type (expr));
+ auto result = (expr_return_place != INVALID_PLACE)
+ ? expr_return_place
+ : ctx.place_db.add_temporary (type);
+ expr_return_place = INVALID_PLACE;
+ return result;
}
};
+/**
+ * Helper to convert a pointer to an optional. Maps nullptr to nullopt.
+ * Optionals are mainly used here to provide monadic operations (map) over
+ * possibly null pointers.
+ */
+template <typename T>
+tl::optional<T>
+optional_from_ptr (T ptr)
+{
+ if (ptr != nullptr)
+ return {ptr};
+ else
+ return tl::nullopt;
+}
+
} // namespace BIR
} // namespace Rust
* Special builder is needed to store short-circuiting context for directly
* nested lazy boolean expressions.
*/
-class LazyBooleanExprBuilder : public AbstractBuilder,
- public HIR::HIRExpressionVisitor
+class LazyBooleanExprBuilder : public AbstractExprBuilder
{
BasicBlockId short_circuit_bb;
public:
- explicit LazyBooleanExprBuilder (BuilderContext &ctx)
- : AbstractBuilder (ctx), short_circuit_bb (0)
+ explicit LazyBooleanExprBuilder (BuilderContext &ctx,
+ PlaceId expr_return_place = INVALID_PLACE)
+ : AbstractExprBuilder (ctx, expr_return_place), short_circuit_bb (0)
{}
PlaceId build (HIR::LazyBooleanExpr &expr)
{
- PlaceId return_place = ctx.place_db.add_temporary (lookup_type (expr));
+ PlaceId return_place = take_or_create_return_place (lookup_type (expr));
short_circuit_bb = new_bb ();
- visit (expr);
- push_assignment (return_place, translated);
+ push_assignment (return_place, visit_expr (expr));
auto final_bb = new_bb ();
push_goto (final_bb);
ctx.current_bb = short_circuit_bb;
- translated = ctx.place_db.get_constant (lookup_type (expr));
- push_assignment (return_place, translated);
+ push_assignment (return_place,
+ ctx.place_db.get_constant (lookup_type (expr)));
push_goto (final_bb);
ctx.current_bb = final_bb;
protected:
void visit (HIR::LazyBooleanExpr &expr) override
{
- expr.get_lhs ()->accept_vis (*this);
- push_switch (translated, {short_circuit_bb});
+ auto lhs = visit_expr (*expr.get_lhs ());
+ push_switch (make_arg (lhs), {short_circuit_bb});
- start_new_subsequent_bb ();
- expr.get_rhs ()->accept_vis (*this);
+ start_new_consecutive_bb ();
+ return_place (visit_expr (*expr.get_rhs ()));
}
void visit (HIR::GroupedExpr &expr) override
{
public:
void visit (HIR::QualifiedPathInExpression &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::PathInExpression &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::ClosureExpr &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::StructExprStructFields &fields) override
{
}
void visit (HIR::LiteralExpr &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::BorrowExpr &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::DereferenceExpr &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::ErrorPropagationExpr &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::NegationExpr &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::ArithmeticOrLogicalExpr &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::ComparisonExpr &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::TypeCastExpr &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::AssignmentExpr &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::CompoundAssignmentExpr &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::ArrayExpr &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::ArrayIndexExpr &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::TupleExpr &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::TupleIndexExpr &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::CallExpr &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::MethodCallExpr &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::FieldAccessExpr &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::BlockExpr &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::UnsafeBlockExpr &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::LoopExpr &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::WhileLoopExpr &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::WhileLetLoopExpr &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::IfExpr &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::IfExprConseqElse &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::IfLetExpr &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::IfLetExprConseqElse &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::MatchExpr &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::AwaitExpr &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
void visit (HIR::AsyncBlockExpr &expr) override
{
- translated = ExprStmtBuilder (ctx).build (expr);
+ return_place (ExprStmtBuilder (ctx).build (expr));
}
protected: // Illegal at this position.
namespace Rust {
namespace BIR {
-// Compiles binding of values into newly created variables.
-// Used in let, match arm, and function parameter patterns.
+
+/**
+ * Compiles binding of values into newly created variables.
+ * Used in let, match arm, and function parameter patterns.
+ */
class PatternBindingBuilder : protected AbstractBuilder,
public HIR::HIRPatternVisitor
{
+ /** Value of initialization expression. */
PlaceId init;
- // This is where lifetime annotations are stored.
+ /** This is where lifetime annotations are stored. */
tl::optional<HIR::Type *> type;
- // Emulates recursive stack saving and restoring inside a visitor.
+ /** Emulates recursive stack saving and restoring inside a visitor. */
class SavedState
{
PatternBindingBuilder *builder;
public:
PatternBindingBuilder (BuilderContext &ctx, PlaceId init, HIR::Type *type)
- : AbstractBuilder (ctx), init (init),
- type (type ? tl::optional<HIR::Type *> (type) : tl::nullopt)
+ : AbstractBuilder (ctx), init (init), type (optional_from_ptr (type))
{}
void go (HIR::Pattern &pattern) { pattern.accept_vis (*this); }
- void visit_identifier (const Analysis::NodeMapping &node, bool is_ref)
+ void visit_identifier (const Analysis::NodeMapping &node, bool is_ref,
+ bool is_mut = false)
{
- translated = declare_variable (node);
if (is_ref)
{
+ translated = declare_variable (
+ node, new TyTy::ReferenceType (node.get_hirid (),
+ TyTy::TyVar (node.get_hirid ()),
+ (is_mut) ? Mutability::Mut
+ : Mutability::Imm));
push_assignment (translated, new BorrowExpr (init));
}
else
{
+ translated = declare_variable (node);
push_assignment (translated, init);
}
auto &init_place = ctx.place_db[init];
{
// Top-level identifiers are resolved directly to avoid useless temporary
// (for cleaner BIR).
- visit_identifier (pattern.get_mappings (), pattern.get_is_ref ());
+ visit_identifier (pattern.get_mappings (), pattern.get_is_ref (),
+ pattern.is_mut ());
}
+
void visit (HIR::ReferencePattern &pattern) override
{
SavedState saved (this);
= ctx.lookup_lifetime (ref_type.map (&HIR::ReferenceType::get_lifetime));
pattern.get_referenced_pattern ()->accept_vis (*this);
}
+
void visit (HIR::SlicePattern &pattern) override
{
SavedState saved (this);
item->accept_vis (*this);
}
}
+
void visit (HIR::AltPattern &pattern) override
{
rust_sorry_at (pattern.get_locus (),
"borrow-checking of alt patterns is not yet implemented");
}
+
void visit (HIR::StructPattern &pattern) override
{
SavedState saved (this);
field_ty->get_field_type (),
saved.init, field_index);
visit_identifier (ident_field->get_mappings (),
- ident_field->get_has_ref ());
+ ident_field->get_has_ref (),
+ ident_field->is_mut ());
break;
}
}
}
}
+
void visit_tuple_fields (std::vector<std::unique_ptr<HIR::Pattern>> &fields,
SavedState &saved, size_t &index)
{
class StructBuilder : public AbstractBuilder, public HIR::HIRFullVisitor
{
TyTy::VariantDef *struct_ty;
+ /** Output of the builder. */
std::vector<PlaceId> init_values;
public:
void visit (HIR::StructExprFieldIdentifier &field) override
{
- resolve_variable (field, translated);
- handle_named_field (field);
+ handle_named_field (field, resolve_variable (field));
}
void visit (HIR::StructExprFieldIdentifierValue &field) override
{
- translated = ExprStmtBuilder (ctx).build (*field.get_value ());
- handle_named_field (field);
+ auto value = ExprStmtBuilder (ctx).build (*field.get_value ());
+ handle_named_field (field, value);
}
void visit (HIR::StructExprFieldIndexValue &field) override
{
- translated = ExprStmtBuilder (ctx).build (*field.get_value ());
- coercion_site (translated,
+ auto value = ExprStmtBuilder (ctx).build (*field.get_value ());
+ coercion_site (value,
struct_ty->get_field_at_index (field.get_tuple_index ())
->get_field_type ());
- init_values.push_back (translated);
+ init_values.push_back (value);
}
private:
- template <typename T> void handle_named_field (T &field)
+ template <typename T> void handle_named_field (T &field, PlaceId value)
{
size_t field_index;
TyTy::StructFieldType *field_type;
bool ok = struct_ty->lookup_field (field.get_field_name ().as_string (),
&field_type, &field_index);
rust_assert (ok);
- rust_assert (translated != INVALID_PLACE);
- coercion_site (translated, field_type->get_field_type ());
- init_values.push_back (translated);
+ rust_assert (value != INVALID_PLACE);
+ coercion_site (value, field_type->get_field_type ());
+ init_values.push_back (value);
}
protected:
void handle_body (HIR::BlockExpr &body)
{
translated = ExprStmtBuilder (ctx).build (body);
- if (body.has_expr ())
+ if (body.has_expr () && !lookup_type (body)->is_unit ())
{
push_assignment (RETURN_VALUE_PLACE, translated);
ctx.get_current_bb ().statements.emplace_back (Node::Kind::RETURN);
}
- }
+ else if (!ctx.get_current_bb ().is_terminated ())
+ {
+ push_assignment (RETURN_VALUE_PLACE,
+ ctx.place_db.get_constant (lookup_type (body)));
+ ctx.get_current_bb ().statements.emplace_back (Node::Kind::RETURN);
+ }
+ };
};
} // namespace BIR
stream << "fn " << name << "(";
print_comma_separated (stream, func.arguments, [this] (PlaceId place_id) {
stream << "_" << place_map[place_id] << ": "
- << get_tyty_name (place_db[place_id].tyty);
+ << get_tyty_name (func.place_db[place_id].tyty);
});
- stream << ") -> " << get_tyty_name (place_db[RETURN_VALUE_PLACE].tyty)
+ stream << ") -> " << get_tyty_name (func.place_db[RETURN_VALUE_PLACE].tyty)
<< " {\n";
- for (PlaceId id = FIRST_VARIABLE_PLACE; id < place_db.size (); ++id)
+ // Print locals declaration.
+ for (PlaceId id = FIRST_VARIABLE_PLACE; id < func.place_db.size (); ++id)
{
- const Place &place = place_db[id];
+ const Place &place = func.place_db[id];
if (place.kind == Place::VARIABLE || place.kind == Place::TEMPORARY)
{
if (std::find (func.arguments.begin (), func.arguments.end (), id)
!= func.arguments.end ())
continue;
- stream << indentation << "let _" << place_map[id] << ": "
- << get_tyty_name (place_db[id].tyty) << ";\n";
+ stream << indentation << "let _";
+ stream << place_map[id] << ": "
+ << get_tyty_name (func.place_db[id].tyty) << ";\n";
}
}
+ // Print BBs.
for (node_bb = 0; node_bb < func.basic_blocks.size (); ++node_bb)
{
if (bb_fold_map[node_bb] != node_bb)
&& func.basic_blocks[node_bb].successors.empty ())
continue;
+ bb_terminated = false;
+
BasicBlock &bb = func.basic_blocks[node_bb];
stream << "\n";
stream << indentation << "bb" << bb_fold_map[node_bb] << ": {\n";
visit (stmt);
stream << ";\n";
}
+ if (!bb_terminated)
+ {
+ stream << indentation << indentation << "goto -> bb"
+ << bb_fold_map[bb.successors.at (0)] << ";\n";
+ }
stream << indentation << "}\n";
}
- stream << "}\n\n";
+ stream << "}\n";
}
void
Dump::visit (Node &node)
switch (node.get_kind ())
{
case Node::Kind::ASSIGNMENT: {
- stream << "_" << place_map[node.get_place ()] << " = ";
+ visit_place (node.get_place ());
+ stream << " = ";
node.get_expr ().accept_vis (*this);
break;
}
stream << "bb" << bb_fold_map[succ];
});
stream << "]";
+ bb_terminated = true;
break;
case Node::Kind::RETURN:
stream << "return";
+ bb_terminated = true;
break;
case Node::Kind::GOTO:
stream << "goto -> bb"
<< bb_fold_map[func.basic_blocks[node_bb].successors.at (0)];
+ bb_terminated = true;
break;
case Node::Kind::STORAGE_DEAD:
stream << "StorageDead(";
void
Dump::visit_place (PlaceId place_id)
{
- const Place &place = place_db[place_id];
+ const Place &place = func.place_db[place_id];
switch (place.kind)
{
case Place::TEMPORARY:
void
Dump::visit_move_place (PlaceId place_id)
{
- const Place &place = place_db[place_id];
- if (!place.is_copy)
+ const Place &place = func.place_db[place_id];
+ if (place.is_rvalue || !place.is_copy)
stream << "move ";
visit_place (place_id);
}
void
Dump::visit_lifetime (PlaceId place_id)
{
- const Place &place = place_db[place_id];
+ const Place &place = func.place_db[place_id];
if (place.lifetime.has_lifetime ())
{
if (place.lifetime.id == STATIC_LIFETIME_ID)
{
stream << "Call(";
if (auto fn_type
- = place_db[expr.get_callable ()].tyty->try_as<TyTy::FnType> ())
+ = func.place_db[expr.get_callable ()].tyty->try_as<TyTy::FnType> ())
{
stream << fn_type->get_identifier ();
}
visit_move_place (expr.get_callable ());
}
stream << ")(";
- for (auto &place : expr.get_arguments ())
- {
- visit_move_place (place);
- stream << ", ";
- }
+ print_comma_separated (stream, expr.get_arguments (),
+ [this] (PlaceId place_id) {
+ visit_move_place (place_id);
+ });
stream << ") -> [";
- print_comma_separated (stream,
- func.basic_blocks[bb_fold_map[node_bb]].successors,
- [this] (const BasicBlockId &dst) {
- stream << "bb" << bb_fold_map[dst];
+ print_comma_separated (stream, func.basic_blocks[node_bb].successors,
+ [this] (BasicBlockId succ) {
+ stream << "bb" << bb_fold_map[succ];
});
stream << "]";
+ bb_terminated = true;
}
void
namespace Rust {
namespace BIR {
+/** Prints the BIR to a stream in a format resembling rustc's MIR. */
class Dump : public Visitor
{
std::ostream &stream;
- const PlaceDB &place_db;
Function &func;
const std::string &name;
PlaceId node_place = INVALID_PLACE;
BasicBlockId node_bb = INVALID_BB;
+ bool bb_terminated = false;
public:
Dump (std::ostream &os, Function &func, const std::string &name)
- : stream (os), place_db (func.place_db), func (func), name (name),
+ : stream (os), func (func), name (name),
bb_fold_map (func.basic_blocks.size ()), place_map (func.place_db.size ())
{}
void go (bool enable_simplify_cfg = false);
0);
}
- PlaceId lookup_variable (NodeId id)
- {
- PlaceId current = FIRST_VARIABLE_PLACE;
-
- while (current != places.size ())
- {
- if (places[current].kind == Place::VARIABLE
- && places[current].variable_or_field_index == id)
- return current;
- current++;
- }
- return INVALID_PLACE;
- };
-
- PlaceId add_temporary (TyTy::BaseType *tyty)
- {
- return add_place (
- {Place::TEMPORARY, 0, {}, is_type_copy (tyty), false, NO_LIFETIME, tyty},
- 0);
- }
-
- WARN_UNUSED_RESULT PlaceId lookup_or_add_path (Place::Kind kind,
- TyTy::BaseType *tyty,
- PlaceId parent, size_t id = 0)
+ [[nodiscard]] PlaceId lookup_or_add_path (Place::Kind kind,
+ TyTy::BaseType *tyty,
+ PlaceId parent, size_t id = 0)
{
PlaceId current = 0;
if (parent < places.size ())
current);
}
+ PlaceId add_temporary (TyTy::BaseType *tyty)
+ {
+ return add_place (
+ {Place::TEMPORARY, 0, {}, is_type_copy (tyty), false, NO_LIFETIME, tyty},
+ 0);
+ }
+
PlaceId get_constant (TyTy::BaseType *tyty)
{
auto lookup = constants_lookup.find (tyty);
return places.size () - 1;
}
+ PlaceId lookup_variable (NodeId id)
+ {
+ PlaceId current = FIRST_VARIABLE_PLACE;
+
+ while (current != places.size ())
+ {
+ if (places[current].kind == Place::VARIABLE
+ && places[current].variable_or_field_index == id)
+ return current;
+ current++;
+ }
+ return INVALID_PLACE;
+ };
+
+ PlaceId lookup_or_add_variable (NodeId id, TyTy::BaseType *tyty)
+ {
+ auto lookup = lookup_variable (id);
+ if (lookup != INVALID_PLACE)
+ return lookup;
+ places.push_back (
+ {Place::VARIABLE, id, {}, is_type_copy (tyty), false, NO_LIFETIME, tyty});
+ return places.size () - 1;
+ };
+
+ PlaceId into_rvalue (PlaceId place)
+ {
+ if (places[place].is_rvalue || places[place].kind == Place::CONSTANT
+ || places[place].tyty->get_kind () == TyTy::REF)
+ return place;
+ return add_place ({Place::TEMPORARY,
+ 0,
+ {},
+ places[place].is_copy,
+ true,
+ NO_LIFETIME,
+ places[place].tyty});
+ }
+
private:
static bool is_type_copy (TyTy::BaseType *ty)
{