sway_core/
engine_threading.rs

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