summaryrefslogtreecommitdiff
path: root/src/mir/from_hir.hpp
blob: ae9c80c8a7cfa36d654d151d73b796d849509cca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/*
 * MRustC - Rust Compiler
 * - By John Hodge (Mutabah/thePowersGang)
 *
 * mir/from_hir.hpp
 * - Construction of MIR from the HIR expression tree
 */
#pragma once
#include "mir.hpp"
#include <hir/type.hpp>
#include <hir/expr.hpp> // for ExprNode_Match
#include <hir_typeck/static.hpp>    // StaticTraitResolve for Copy

class MirBuilder;

class ScopeHandle
{
    friend class MirBuilder;
    
    const MirBuilder& m_builder;
    unsigned int    idx;
    
    ScopeHandle(const MirBuilder& builder, unsigned int idx):
        m_builder(builder),
        idx(idx)
    {
    }
public:
    ScopeHandle(const ScopeHandle& x) = delete;
    ScopeHandle(ScopeHandle&& x):
        m_builder(x.m_builder),
        idx(x.idx)
    {
        x.idx = ~0;
    }
    ScopeHandle& operator=(const ScopeHandle& x) = delete;
    ScopeHandle& operator=(ScopeHandle&& x) = delete;
    ~ScopeHandle();
};

enum class VarState {
    Uninit, // No value assigned yet
    Init,   // Initialised and valid at this point
    MaybeMoved, // Possibly has been moved
    Moved,  // Definitely moved
    Dropped,    // Dropped (out of scope)
};
extern ::std::ostream& operator<<(::std::ostream& os, VarState x);

struct SplitArm {
    bool    has_early_terminated = false;
    bool    always_early_terminated = false;    // Populated on completion
    ::std::vector<bool> changed_var_states; // Indexed by binding bumber
    ::std::vector<VarState> var_states;
};

TAGGED_UNION(ScopeType, Variables,
    (Variables, struct {
        ::std::vector<unsigned int> vars;   // List of owned variables
        ::std::vector<VarState> var_states; // Indexed by position in above list
        }),
    (Temporaries, struct {
        ::std::vector<unsigned int> temporaries;    // Controlled temporaries
        ::std::vector<VarState> states; // Indexed by position in above list
        }),
    (Split, struct {
        ::std::vector<SplitArm> arms;
        }),
    (Loop, struct {
        })
    );

/// Helper class to construct MIR
class MirBuilder
{
    friend class ScopeHandle;
    
    const StaticTraitResolve& m_resolve;
    ::MIR::Function&    m_output;
    
    unsigned int    m_current_block;
    bool    m_block_active;
    
    ::MIR::RValue   m_result;
    bool    m_result_valid;
    
    ::std::vector<bool> variables_valid;
    ::std::vector<bool> temporaries_valid;
    
    struct ScopeDef
    {
        bool complete = false;
        ScopeType   data;
    };
    
    ::std::vector<ScopeDef> m_scopes;
    ::std::vector<unsigned int> m_scope_stack;
    ScopeHandle m_fcn_scope;
public:
    MirBuilder(const StaticTraitResolve& resolve, ::MIR::Function& output);
    ~MirBuilder();
    
    const ::HIR::Crate& crate() const { return m_resolve.m_crate; }
    
    // - Values
    ::MIR::LValue new_temporary(const ::HIR::TypeRef& ty);
    ::MIR::LValue lvalue_or_temp(const ::HIR::TypeRef& ty, ::MIR::RValue val);
    
    bool has_result() const {
        return m_result_valid;
    }
    ::MIR::RValue get_result(const Span& sp);
    ::MIR::LValue get_result_lvalue(const Span& sp);
    void set_result(const Span& sp, ::MIR::RValue val);
    
    // - Statements
    // Push an assignment. NOTE: This also marks the rvalue as moved
    void push_stmt_assign(::MIR::LValue dst, ::MIR::RValue val);
    // Push a drop (likely only used by scope cleanup)
    void push_stmt_drop(::MIR::LValue val);
    
    // - Block management
    bool block_active() const {
        return m_block_active;
    }
    
    void set_cur_block(unsigned int new_block);
    ::MIR::BasicBlockId pause_cur_block();
    void end_block(::MIR::Terminator term);
    
    ::MIR::BasicBlockId new_bb_linked();
    ::MIR::BasicBlockId new_bb_unlinked();
    
    // --- Scopes ---
    ScopeHandle new_scope_var(const Span& sp);
    ScopeHandle new_scope_temp(const Span& sp);
    ScopeHandle new_scope_split(const Span& sp);
    ScopeHandle new_scope_loop(const Span& sp);
    void terminate_scope(const Span& sp, ScopeHandle );
    void terminate_scope_early(const Span& sp, const ScopeHandle& );
    void end_split_arm(const Span& sp, const ScopeHandle& , bool reachable);
    
    const ScopeHandle& fcn_scope() const {
        return m_fcn_scope;
    }

    /// Introduce a new variable within the current scope
    void define_variable(unsigned int idx);
    // Helper - Marks a variable/... as moved (and checks if the move is valid)
    void moved_lvalue(const ::MIR::LValue& lv);
private:
    VarState get_variable_state(unsigned int idx) const;
    void set_variable_state(unsigned int idx, VarState state);
    VarState get_temp_state(unsigned int idx) const;
    void set_temp_state(unsigned int idx, VarState state);
    
    void drop_scope_values(const ScopeDef& sd);
    void complete_scope(ScopeDef& sd);
    
    void with_val_type(const ::MIR::LValue& val, ::std::function<void(const ::HIR::TypeRef&)> cb);
    bool lvalue_is_copy(const ::MIR::LValue& lv);
};

class MirConverter:
    public ::HIR::ExprVisitor
{
public:
    virtual void destructure_from(const Span& sp, const ::HIR::Pattern& pat, ::MIR::LValue lval, bool allow_refutable=false) = 0;
    virtual void define_vars_from(const Span& sp, const ::HIR::Pattern& pat) = 0;
};

extern void MIR_LowerHIR_Match(MirBuilder& builder, MirConverter& conv, ::HIR::ExprNode_Match& node, ::MIR::LValue match_val);