sway_ir/
context.rs

1//! The main handle to an IR instance.
2//!
3//! [`Context`] contains several
4//! [slotmap](https://github.com/orlp/slotmap) collections to maintain the
5//! IR ECS.
6//!
7//! It is passed around as a mutable reference to many of the Sway-IR APIs.
8
9use rustc_hash::FxHashMap;
10use slotmap::{DefaultKey, SlotMap};
11use sway_features::ExperimentalFeatures;
12use sway_types::SourceEngine;
13
14use crate::{
15    block::BlockContent,
16    function::FunctionContent,
17    metadata::Metadatum,
18    module::{Kind, ModuleContent, ModuleIterator},
19    value::ValueContent,
20    variable::LocalVarContent,
21    Constant, ConstantContent, GlobalVarContent, StorageKeyContent, Type, TypeContent,
22};
23
24// Copy of `sway_core::build_config::Backtrace`, which cannot
25// be used here directly due to circular dependency.
26#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
27pub enum Backtrace {
28    All,
29    #[default]
30    AllExceptNever,
31    OnlyAlways,
32    None,
33}
34
35/// The main IR context handle.
36///
37/// Every module, function, block and value is stored here.  Some aggregate metadata is also
38/// managed by the context.
39pub struct Context<'eng> {
40    pub source_engine: &'eng SourceEngine,
41
42    pub(crate) modules: SlotMap<DefaultKey, ModuleContent>,
43    pub(crate) functions: SlotMap<DefaultKey, FunctionContent>,
44    pub(crate) blocks: SlotMap<DefaultKey, BlockContent>,
45    pub(crate) values: SlotMap<DefaultKey, ValueContent>,
46    pub(crate) local_vars: SlotMap<DefaultKey, LocalVarContent>,
47    pub(crate) global_vars: SlotMap<DefaultKey, GlobalVarContent>,
48    pub(crate) storage_keys: SlotMap<DefaultKey, StorageKeyContent>,
49    pub(crate) types: SlotMap<DefaultKey, TypeContent>,
50    pub(crate) type_map: FxHashMap<TypeContent, Type>,
51    pub(crate) constants: SlotMap<DefaultKey, ConstantContent>,
52    // Maps the hash of a ConstantContent to the list of constants with that hash.
53    pub(crate) constants_map: FxHashMap<u64, Vec<Constant>>,
54
55    pub(crate) metadata: SlotMap<DefaultKey, Metadatum>,
56
57    pub program_kind: Kind,
58
59    pub experimental: ExperimentalFeatures,
60    pub backtrace: Backtrace,
61
62    next_unique_sym_tag: u64,
63    next_unique_panic_error_code: u64,
64    next_unique_panicking_call_id: u64,
65}
66
67impl<'eng> Context<'eng> {
68    pub fn new(
69        source_engine: &'eng SourceEngine,
70        experimental: ExperimentalFeatures,
71        backtrace: Backtrace,
72    ) -> Self {
73        let mut def = Self {
74            source_engine,
75            modules: Default::default(),
76            functions: Default::default(),
77            blocks: Default::default(),
78            values: Default::default(),
79            local_vars: Default::default(),
80            global_vars: Default::default(),
81            storage_keys: Default::default(),
82            types: Default::default(),
83            type_map: Default::default(),
84            constants: Default::default(),
85            constants_map: Default::default(),
86            metadata: Default::default(),
87            next_unique_sym_tag: 0,
88            next_unique_panic_error_code: 0,
89            // The next unique panicking call ID starts at 1, as 0 is reserved
90            // for the "there was no panicking call" case.
91            next_unique_panicking_call_id: 1,
92            program_kind: Kind::Contract,
93            experimental,
94            backtrace,
95        };
96        Type::create_basic_types(&mut def);
97        def
98    }
99
100    pub fn source_engine(&self) -> &'eng SourceEngine {
101        self.source_engine
102    }
103
104    /// Return an iterator for every module in this context.
105    pub fn module_iter(&self) -> ModuleIterator {
106        ModuleIterator::new(self)
107    }
108
109    /// Get a globally unique symbol.
110    ///
111    /// The name will be in the form `"anon_N"`, where `N` is an incrementing decimal.
112    pub fn get_unique_name(&mut self) -> String {
113        format!("anon_{}", self.get_unique_symbol_id())
114    }
115
116    /// Get a globally unique symbol id.
117    pub fn get_unique_symbol_id(&mut self) -> u64 {
118        let sym = self.next_unique_sym_tag;
119        self.next_unique_sym_tag += 1;
120        sym
121    }
122
123    /// Get the next, unique, panic error code.
124    pub fn get_unique_panic_error_code(&mut self) -> u64 {
125        let code = self.next_unique_panic_error_code;
126        self.next_unique_panic_error_code += 1;
127        code
128    }
129
130    /// Get the next, unique, panicking call ID.
131    pub fn get_unique_panicking_call_id(&mut self) -> u64 {
132        let id = self.next_unique_panicking_call_id;
133        self.next_unique_panicking_call_id += 1;
134        id
135    }
136}
137
138use std::fmt::{Display, Error, Formatter};
139
140impl Display for Context<'_> {
141    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
142        write!(f, "{}", crate::printer::to_string(self))
143    }
144}
145
146impl From<Context<'_>> for String {
147    fn from(context: Context) -> Self {
148        crate::printer::to_string(&context)
149    }
150}