sway_core/
engine_threading.rs

1use crate::{
2    decl_engine::{parsed_engine::ParsedDeclEngine, DeclEngine},
3    language::CallPath,
4    query_engine::QueryEngine,
5    type_system::TypeEngine,
6    ObservabilityEngine,
7};
8use std::{
9    cmp::Ordering,
10    fmt,
11    hash::{BuildHasher, Hash, Hasher},
12    sync::Arc,
13};
14use sway_types::{SourceEngine, Span};
15
16#[derive(Clone, Debug, Default)]
17pub struct Engines {
18    type_engine: TypeEngine,
19    decl_engine: DeclEngine,
20    parsed_decl_engine: ParsedDeclEngine,
21    query_engine: QueryEngine,
22    source_engine: SourceEngine,
23    obs_engine: Arc<ObservabilityEngine>,
24}
25
26impl Engines {
27    pub fn te(&self) -> &TypeEngine {
28        &self.type_engine
29    }
30
31    pub fn de(&self) -> &DeclEngine {
32        &self.decl_engine
33    }
34
35    pub fn pe(&self) -> &ParsedDeclEngine {
36        &self.parsed_decl_engine
37    }
38
39    pub fn qe(&self) -> &QueryEngine {
40        &self.query_engine
41    }
42
43    pub fn se(&self) -> &SourceEngine {
44        &self.source_engine
45    }
46
47    pub fn obs(&self) -> &ObservabilityEngine {
48        &self.obs_engine
49    }
50
51    /// Removes all data associated with `program_id` from the engines.
52    /// It is intended to be used during garbage collection to remove any data that is no longer needed.
53    pub fn clear_program(&mut self, program_id: &sway_types::ProgramId) {
54        self.type_engine.clear_program(program_id);
55        self.decl_engine.clear_program(program_id);
56        self.parsed_decl_engine.clear_program(program_id);
57        self.query_engine.clear_program(program_id);
58    }
59
60    /// Removes all data associated with `source_id` from the engines.
61    /// It is intended to be used during garbage collection to remove any data that is no longer needed.
62    ///
63    /// It will also clear the associated autogenerated file for the `source_id` parameter.
64    pub fn clear_module(&mut self, source_id: &sway_types::SourceId) {
65        self.type_engine.clear_module(source_id);
66        self.decl_engine.clear_module(source_id);
67        self.parsed_decl_engine.clear_module(source_id);
68        self.query_engine.clear_module(source_id);
69
70        // Check if `source_id` has an associated autogenerated file
71        // and clear it
72        if let Some(autogenerated_source_id) =
73            self.se().get_associated_autogenerated_source_id(source_id)
74        {
75            if autogenerated_source_id == *source_id {
76                return;
77            }
78
79            self.type_engine.clear_module(&autogenerated_source_id);
80            self.decl_engine.clear_module(&autogenerated_source_id);
81            self.parsed_decl_engine
82                .clear_module(&autogenerated_source_id);
83            self.query_engine.clear_module(&autogenerated_source_id);
84        }
85    }
86
87    /// Helps out some `thing: T` by adding `self` as context.
88    pub fn help_out<T>(&self, thing: T) -> WithEngines<'_, T> {
89        WithEngines {
90            thing,
91            engines: self,
92        }
93    }
94}
95
96#[derive(Clone, Copy)]
97pub struct WithEngines<'a, T> {
98    pub thing: T,
99    pub engines: &'a Engines,
100}
101
102impl<'a, T> WithEngines<'a, T> {
103    pub fn new(thing: T, engines: &'a Engines) -> Self {
104        WithEngines { thing, engines }
105    }
106}
107
108/// Displays the user-friendly formatted view of `thing` using `engines` as context.
109impl<T: DisplayWithEngines> fmt::Display for WithEngines<'_, T> {
110    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111        self.thing.fmt(f, self.engines)
112    }
113}
114
115/// Displays the internals of `thing` using `engines` as context. Useful for debugging.
116impl<T: DebugWithEngines> fmt::Debug for WithEngines<'_, T> {
117    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118        self.thing.fmt(f, self.engines)
119    }
120}
121
122impl<T: HashWithEngines> Hash for WithEngines<'_, T> {
123    fn hash<H: Hasher>(&self, state: &mut H) {
124        self.thing.hash(state, self.engines)
125    }
126}
127
128impl<T: PartialEqWithEngines> PartialEq for WithEngines<'_, T> {
129    fn eq(&self, rhs: &Self) -> bool {
130        self.thing
131            .eq(&rhs.thing, &PartialEqWithEnginesContext::new(self.engines))
132    }
133}
134
135impl<T: EqWithEngines> Eq for WithEngines<'_, T> {}
136
137impl<T: OrdWithEngines> PartialOrd for WithEngines<'_, T>
138where
139    T: PartialEqWithEngines,
140{
141    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
142        Some(
143            self.thing
144                .cmp(&other.thing, &OrdWithEnginesContext::new(self.engines)),
145        )
146    }
147}
148
149impl<T: OrdWithEngines> Ord for WithEngines<'_, T>
150where
151    T: EqWithEngines,
152{
153    fn cmp(&self, other: &Self) -> Ordering {
154        self.thing
155            .cmp(&other.thing, &OrdWithEnginesContext::new(self.engines))
156    }
157}
158
159pub(crate) trait DisplayWithEngines {
160    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result;
161}
162
163impl<T: DisplayWithEngines> DisplayWithEngines for &T {
164    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
165        (*self).fmt(f, engines)
166    }
167}
168
169impl<T: DisplayWithEngines> DisplayWithEngines for Option<T> {
170    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
171        match self {
172            None => Ok(()),
173            Some(x) => x.fmt(f, engines),
174        }
175    }
176}
177
178impl<T: DisplayWithEngines> DisplayWithEngines for Box<T> {
179    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
180        (**self).fmt(f, engines)
181    }
182}
183
184impl<T: DisplayWithEngines> DisplayWithEngines for Vec<T> {
185    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
186        let text = self
187            .iter()
188            .map(|e| format!("{}", engines.help_out(e)))
189            .collect::<Vec<_>>()
190            .join(", ")
191            .to_string();
192        f.write_str(&text)
193    }
194}
195
196impl DisplayWithEngines for Span {
197    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
198        let file = self
199            .source_id()
200            .and_then(|id| engines.source_engine.get_file_name(id));
201        f.write_fmt(format_args!(
202            "Span {{ {:?}, {} }}",
203            file,
204            self.line_col_one_index()
205        ))
206    }
207}
208
209pub(crate) trait DebugWithEngines {
210    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result;
211}
212
213impl<T: DebugWithEngines> DebugWithEngines for &T {
214    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
215        (*self).fmt(f, engines)
216    }
217}
218
219impl<T: DebugWithEngines> DebugWithEngines for std::sync::Arc<T> {
220    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
221        (**self).fmt(f, engines)
222    }
223}
224
225impl<T: DebugWithEngines> DebugWithEngines for Option<T> {
226    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
227        match self {
228            None => Ok(()),
229            Some(x) => x.fmt(f, engines),
230        }
231    }
232}
233
234impl<T: DebugWithEngines> DebugWithEngines for Box<T> {
235    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
236        (**self).fmt(f, engines)
237    }
238}
239
240impl<T: DebugWithEngines> DebugWithEngines for Vec<T> {
241    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
242        let text = self
243            .iter()
244            .map(|e| format!("{:?}", engines.help_out(e)))
245            .collect::<Vec<_>>()
246            .join(", ")
247            .to_string();
248        f.write_str(&text)
249    }
250}
251
252impl DebugWithEngines for Span {
253    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
254        DisplayWithEngines::fmt(self, f, engines)
255    }
256}
257
258pub trait HashWithEngines {
259    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines);
260}
261
262impl<T: HashWithEngines + ?Sized> HashWithEngines for &T {
263    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
264        (*self).hash(state, engines)
265    }
266}
267
268impl<T: HashWithEngines> HashWithEngines for Option<T> {
269    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
270        match self {
271            None => state.write_u8(0),
272            Some(x) => x.hash(state, engines),
273        }
274    }
275}
276
277impl<T: HashWithEngines> HashWithEngines for [T] {
278    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
279        for x in self {
280            x.hash(state, engines)
281        }
282    }
283}
284
285impl<T: HashWithEngines> HashWithEngines for Box<T> {
286    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
287        (**self).hash(state, engines)
288    }
289}
290
291impl<T: HashWithEngines> HashWithEngines for Arc<T> {
292    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
293        (**self).hash(state, engines)
294    }
295}
296
297pub trait EqWithEngines: PartialEqWithEngines {}
298
299pub struct PartialEqWithEnginesContext<'a> {
300    engines: &'a Engines,
301    is_inside_trait_constraint: bool,
302}
303
304impl<'a> PartialEqWithEnginesContext<'a> {
305    pub(crate) fn new(engines: &'a Engines) -> Self {
306        Self {
307            engines,
308            is_inside_trait_constraint: false,
309        }
310    }
311
312    pub(crate) fn with_is_inside_trait_constraint(&self) -> Self {
313        Self {
314            is_inside_trait_constraint: true,
315            ..*self
316        }
317    }
318
319    pub(crate) fn engines(&self) -> &Engines {
320        self.engines
321    }
322
323    pub(crate) fn is_inside_trait_constraint(&self) -> bool {
324        self.is_inside_trait_constraint
325    }
326}
327
328pub trait PartialEqWithEngines {
329    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool;
330}
331
332pub struct OrdWithEnginesContext<'a> {
333    engines: &'a Engines,
334    is_inside_trait_constraint: bool,
335}
336
337impl<'a> OrdWithEnginesContext<'a> {
338    pub(crate) fn new(engines: &'a Engines) -> Self {
339        Self {
340            engines,
341            is_inside_trait_constraint: false,
342        }
343    }
344
345    pub(crate) fn with_is_inside_trait_constraint(&self) -> Self {
346        Self {
347            is_inside_trait_constraint: true,
348            ..*self
349        }
350    }
351
352    pub(crate) fn engines(&self) -> &Engines {
353        self.engines
354    }
355
356    pub(crate) fn is_inside_trait_constraint(&self) -> bool {
357        self.is_inside_trait_constraint
358    }
359}
360
361pub trait OrdWithEngines {
362    fn cmp(&self, other: &Self, ctx: &OrdWithEnginesContext) -> Ordering;
363}
364
365impl<T: EqWithEngines + ?Sized> EqWithEngines for &T {}
366impl<T: PartialEqWithEngines + ?Sized> PartialEqWithEngines for &T {
367    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
368        (*self).eq(*other, ctx)
369    }
370}
371impl<T: OrdWithEngines + ?Sized> OrdWithEngines for &T {
372    fn cmp(&self, other: &Self, ctx: &OrdWithEnginesContext) -> Ordering {
373        (*self).cmp(*other, ctx)
374    }
375}
376
377impl<T: OrdWithEngines> OrdWithEngines for Option<T> {
378    fn cmp(&self, other: &Self, ctx: &OrdWithEnginesContext) -> Ordering {
379        match (self, other) {
380            (Some(x), Some(y)) => x.cmp(y, ctx),
381            (Some(_), None) => Ordering::Less,
382            (None, Some(_)) => Ordering::Greater,
383            (None, None) => Ordering::Equal,
384        }
385    }
386}
387
388impl<T: OrdWithEngines> OrdWithEngines for Box<T> {
389    fn cmp(&self, other: &Self, ctx: &OrdWithEnginesContext) -> Ordering {
390        (**self).cmp(&(**other), ctx)
391    }
392}
393
394impl<T: EqWithEngines> EqWithEngines for Option<T> {}
395impl<T: PartialEqWithEngines> PartialEqWithEngines for Option<T> {
396    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
397        match (self, other) {
398            (None, None) => true,
399            (Some(x), Some(y)) => x.eq(y, ctx),
400            _ => false,
401        }
402    }
403}
404
405impl<T: EqWithEngines> EqWithEngines for Box<T> {}
406impl<T: PartialEqWithEngines> PartialEqWithEngines for Box<T> {
407    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
408        (**self).eq(&(**other), ctx)
409    }
410}
411
412impl<T: EqWithEngines> EqWithEngines for [T] {}
413impl<T: PartialEqWithEngines> PartialEqWithEngines for [T] {
414    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
415        self.len() == other.len() && self.iter().zip(other.iter()).all(|(x, y)| x.eq(y, ctx))
416    }
417}
418impl<T: OrdWithEngines> OrdWithEngines for [T] {
419    fn cmp(&self, other: &Self, ctx: &OrdWithEnginesContext) -> Ordering {
420        let len_cmp = self.len().cmp(&other.len());
421        if len_cmp != Ordering::Equal {
422            return len_cmp;
423        }
424
425        for (a, b) in self.iter().zip(other.iter()) {
426            let cmp = a.cmp(b, ctx);
427            if cmp != Ordering::Equal {
428                return cmp;
429            }
430        }
431
432        Ordering::Equal
433    }
434}
435
436pub(crate) fn make_hasher<'a: 'b, 'b, K>(
437    hash_builder: &'a impl BuildHasher,
438    engines: &'b Engines,
439) -> impl Fn(&K) -> u64 + 'b
440where
441    K: HashWithEngines + ?Sized,
442{
443    move |key: &K| {
444        let mut state = hash_builder.build_hasher();
445        key.hash(&mut state, engines);
446        state.finish()
447    }
448}
449
450pub trait SpannedWithEngines {
451    fn span(&self, engines: &Engines) -> Span;
452}
453
454pub trait GetCallPathWithEngines {
455    fn call_path(&self, engines: &Engines) -> Option<CallPath>;
456}