Skip to main content

qcode/value/util/
detached.rs

1//! The detached-body mutation host ([`DetachedMut`]).
2//!
3//! A pass that mints a fresh function builds it *detached*: a [`FunctionBody`]
4//! with **no** registry identity yet ([`FunctionBody::detached`]). `DetachedMut`
5//! is that body's exclusive mutation surface while it is being built — a thin
6//! wrapper exposing **only body-local verbs** (`LocalValueId`/`LocalBlockId`/
7//! `LocalInsnId` in and out). Owner values stay composite ([`ValueId`](crate::value::ValueId)); minted
8//! values are local, so mixing the two is a type error — there is no qualifier in
9//! scope (the detached body's [`id`](FunctionBody::id) panics before install) to
10//! launder an owner id through.
11//!
12//! Every method is a one-line delegation to a `FunctionBody` inherent *local*
13//! verb; none consults [`FunctionBody::id`].
14
15use std::borrow::Cow;
16
17use crate::{
18    builder::Builder,
19    context::Shared,
20    error::Result,
21    types::TypeId,
22    value::{
23        FunctionBody, FunctionId, LocalBlockId, LocalInsnId, LocalParamId, LocalValueId,
24        block::{BasicBlock, EdgeId},
25        block_param::BlockParam,
26        function::FunctionInterface,
27        insn::Mnemonic,
28    },
29};
30
31/// The exclusive mutation host for a **detached** (minted, not-yet-installed)
32/// function body. See the module docs: all verbs are body-local.
33pub struct DetachedMut<'a, 'str> {
34    /// The detached body being built (no registry identity until install).
35    pub body: &'a mut FunctionBody<'str>,
36    /// The module's shared IR state, read-only (types/literals minted through the
37    /// interners' `&self` paths).
38    pub shared: &'a Shared<'str>,
39    /// Every function's published interface (never checked out).
40    pub interfaces: &'a jstd::registry::Registry<FunctionId, FunctionInterface<'str>>,
41}
42
43impl<'a, 'str> DetachedMut<'a, 'str> {
44    /// Wrap `body` over the module's shared state and interface registry.
45    pub fn new(
46        body: &'a mut FunctionBody<'str>,
47        shared: &'a Shared<'str>,
48        interfaces: &'a jstd::registry::Registry<FunctionId, FunctionInterface<'str>>,
49    ) -> Self {
50        Self {
51            body,
52            shared,
53            interfaces,
54        }
55    }
56
57    /// The module's shared IR state ([`Shared`]) (read).
58    pub fn shr(&self) -> &Shared<'str> {
59        self.shared
60    }
61
62    /// Mint a fresh empty block into the detached body.
63    pub fn make_block(&mut self) -> LocalBlockId {
64        self.body.make_block_local()
65    }
66
67    /// Set the detached body's entry block.
68    pub fn set_root(&mut self, root: LocalBlockId) {
69        self.body.set_root_id(Some(root));
70    }
71
72    /// A read of block `block`'s payload (params/instructions/edges).
73    pub fn block(&self, block: LocalBlockId) -> &BasicBlock<'str> {
74        self.body.block_local(block)
75    }
76
77    /// Add a directed CFG edge `from -> to`.
78    pub fn add_cfg_edge(&mut self, from: LocalBlockId, to: LocalBlockId) -> EdgeId {
79        self.body.add_cfg_edge_local(from, to)
80    }
81
82    /// Mint an instruction with `mnemonic` and an explicit result `type_id`.
83    pub fn push_mnemonic_with_type(&mut self, mnemonic: Mnemonic, type_id: TypeId) -> LocalInsnId {
84        self.body.push_mnemonic_with_type_local(mnemonic, type_id)
85    }
86
87    /// Append an already-minted instruction to the end of `block`.
88    pub fn append_insn(&mut self, block: LocalBlockId, insn: LocalInsnId) {
89        self.body.append_insn_local(block, insn);
90    }
91
92    /// Declare a block parameter, wiring it into `block`'s parameter list.
93    pub fn push_block_param(
94        &mut self,
95        block: LocalBlockId,
96        param: BlockParam<'str>,
97    ) -> LocalParamId {
98        self.body.push_block_param_local(block, param)
99    }
100
101    /// Replace instruction `insn`'s mnemonic in place, keeping reverse-uses synced.
102    pub fn replace_instruction_mnemonic(&mut self, insn: LocalInsnId, mnemonic: Mnemonic) {
103        self.body.replace_instruction_mnemonic_local(insn, mnemonic);
104    }
105
106    /// Instruction `insn`'s mnemonic (read).
107    pub fn mnemonic(&self, insn: LocalInsnId) -> &Mnemonic {
108        self.body.mnemonic_local(insn)
109    }
110
111    /// The result type of a body-local operand.
112    pub fn type_of(&self, id: LocalValueId) -> TypeId {
113        self.body.local_type_of(self.shared, id)
114    }
115
116    /// Set and register `block`'s name in the body's local name table.
117    pub fn rename_block(&mut self, block: LocalBlockId, name: Cow<'str, str>) -> Result<()> {
118        self.body.rename_block_local(block, name)
119    }
120
121    /// A builder positioned at `block`, driving the id-less local push surface.
122    pub fn builder(&mut self, block: LocalBlockId) -> Builder<'str, '_> {
123        Builder::new_local(self.body, self.shared, self.interfaces, block)
124    }
125}