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}