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